I have an app that uses the location updates when it is in the foreground as well as in the background. Using the CoreLocation framework, I have implemented the app so that location updates are sent to the server after every 5 minutes, using this code as a reference.
This works fine in foreground, but when the app goes to the background, it is getting killed by the OS after 30 minutes to an hour. I want the app to get updates for at least 8 hours, even in the background.
Also, the app is using the about 10% of the battery per hour. Is this related to the app being killed in the background? If so, then how can I resolve the battery problem? Otherwise, can anyone tell me what the issue is?
Below is the crash log for the device:
Exception Type: 00000020
Exception Codes: 0x000000008badf00d
Exception Note: SIMULATED (this is NOT a crash)
Highlighted by Thread: 2
Application Specific Information:
<BKNewProcess: 0x17e74840; com.app.app; pid: 560; hostpid: -1> has active assertions beyond permitted time:
{(
<BKProcessAssertion: 0x17d78740> id: 560-C9E81E97-90D9-4F95-871E-3DC53372F302 name: Called by UIKit, from <redacted> process: <BKNewProcess: 0x17e74840; com.app.example; pid: 560; hostpid: -1> permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:560 preventSuspend preventIdleSleep preventSuspendOnSleep ,
<BKProcessAssertion: 0x17e6a870> id: 560-BD7B29FC-DABC-42FF-AF17-B277BDB1C59D name: Called by UIKit, from <redacted> process: <BKNewProcess: 0x17e74840; com.app.example; pid: 560; hostpid: -1> permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:560 preventSuspend preventIdleSleep preventSuspendOnSleep
)}
For the background task I use the following function:
func backgroundTask(){
var application=UIApplication.sharedApplication()
var background_task: UIBackgroundTaskIdentifier?
background_task = application.beginBackgroundTaskWithExpirationHandler({() -> Void in
application.endBackgroundTask(background_task!)
background_task = UIBackgroundTaskInvalid
})
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {() -> Void in
//run the app without startUpdatingLocation. backgroundTimeRemaining decremented from 600.00
self.locationManager.startUpdatingLocation()
while (true) {
//backgroundTimeRemaining time does not go down.
print("Background time Remaining: \(UIApplication.sharedApplication().backgroundTimeRemaining)")
NSThread.sleepForTimeInterval(1)
break
//wait for 1 sec
}
application.endBackgroundTask(background_task!)
background_task = UIBackgroundTaskInvalid
})
}
When you start a background task, you have 30 seconds to complete it, and then call endBackgroundTask on it. If you do not call endBackgroundTask, iOS will terminate your app. MXBackgroundExitData can be used to check the count of your background terminations from past usage.
For iOS Devices If Background refresh is greyed out in the ON position, go To Settings App - > General - > Background App Refresh - > Turn on the option for the system, and then you can turn on / off by app.
Access to location is considered in the foreground if it happens while the app is open and visible to the user. If the user closes the app, or hits the home button to return to their main screen, then the app's access to location is considered in the background.
In Android 9 and lower, an app can track a device's location while running in the background without the user's knowledge. Users can suppress this behavior in Android 10 by selecting either the Allow only while using the App or Deny location access permission.
When your app enters in background state switch to significant location updates
and your app will receive location update continuously. you can call startMonitoringSignificantLocationChanges
on CLLocationManger
's object i think. And you not need to establish background task also i think.
Check the Apple Documentation, It states,
If you start this service and your app is subsequently terminated, the system automatically relaunches the app into the background if a new event arrives. In such a case, the options dictionary passed to the application:willFinishLaunchingWithOptions: and application:didFinishLaunchingWithOptions: methods of your app delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your app was launched because of a location event. Upon relaunch, you must still configure a location manager object and call this method to continue receiving location events. When you restart location services, the current event is delivered to your delegate immediately. In addition, the location property of your location manager object is populated with the most recent location object even before you start location services
So, it will solve your problem i think and it will solve issue of battery also.
Second thing (for battery consumption), You should not set DesiredAccuracy
to kCLLocationAccuracyBest
when want to update location in background for long time. You can set kCLLocationAccuracyThreeKilometers
as DesiredAccuracy
and you can set setDistanceFilter
to very big digit like 99999
when enter in background.
You can refer this so post and this so post.
Hope this will help :)
Do you have any crash log.If application not terminated by exception of some hidden bug you should suspicious of memory pressure.I think this article will lead you to find reason of sudden termination
https://www.raywenderlich.com/23704/demystifying-ios-application-crash-logs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With