Reputation: 799
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
})
}
Upvotes: 5
Views: 2390
Reputation: 13537
I am posting this answer because Everyone is said that it is OS default behavior, We can not change it....bla....bla.
Recently, I was working with the same requirement. After 2-3 week hard work, I did it. For other users, I create a helper class for it. My app will never be killed by OS until the location tracking running.
Use HSLocationManager for infinite location tracking in the active and inactive state.
Refer my app which is available in the app store(App will never kill by OS if location tracking is running)
Location manager that allows getting background location updates every n seconds with desired location accuracy.
Advantage:
OS will never kill our app if the location manager is currently running.
Give periodically location update when it required(range is between 2 - 170 seconds (limited by max allowed background task time))
Customizable location accuracy and time period.
Low memory consumption(Singleton class)
Upvotes: 0
Reputation: 299265
As other note, you need to register to receive background location updates. What may not be clear is that this is not the same thing as "running in the background all the time doing whatever you feel like." It means that at various times, at the system's discretion, you will be sent location data, you must deal with that location data as quickly as you can and then return. You will be called again when the system chooses to. There may be other location services running. The system tries to optimize this by coalescing all the different location clients.
Background tasks, like the one you're trying to use, are for a completely different problem. They're to request "a little extra time" to get something done when the user exits the app. Something like clean up your database or the like. If you let them keep running, you'll get killed. Looking at your current code, it doesn't look like it actually does anything though, since it looks like it breaks out of the loop after one call. But any code that calls NSThread.sleepForTimeInterval(1)
is almost guaranteed to be incorrect in iOS. There are almost no reasons ever to make that call. But you shouldn't need a background task to manage location updates.
Upvotes: 0
Reputation: 4065
As @Lion said use Significant Location Change when entering in background. I had the same issue using SLC so you will have it too. When the app was entering the background it was killed by the system due to memory warnings. So what I did it was to create a singleton for CoreLocation which will receive all the delegates calls of CoreLocation.
In order to restart you service in background in case it's getting killed:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
//NSLog(@"Restarting SCL");
LocationService *loc = [LocationService sharedInstance];
[loc setManagedObjectContext:self.managedObjectContext];
}
LocationService is my singleton.
Also implement this function in AppDelegate to handle Memory Warnings Notifications:
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
//Sending notification to every controller to free some memory
[[NSNotificationCenter defaultCenter] postNotificationName:@"freeMemory" object:nil userInfo:nil];
SDImageCache *imageCache = [SDImageCache sharedImageCache];
[imageCache clearMemory];
[imageCache clearDisk];
//NSLog(@"Received memory warning!");
}
For example clear the image cache. Also I you are are using MapView make sure to nullify whatever you don't use since is very expensive view (and buggy with leaks).
Upvotes: 1
Reputation: 27428
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 :)
Upvotes: 3
Reputation: 1006
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
Upvotes: 1