The background task does not seem to be canceled / does not end

We are currently developing an iOS application that needs to be checked in the background. At first we tried to use significant changes in location, but they are not accurate enough / do not work often enough. We examined the use of regional monitoring, but from what I read on the Internet, this is also not always accurate, and you also have the problem of a limited number of regions for monitoring. (We can ultimately try monitoring the region.) Right now, we are trying to use standard location updates to track a user's location in the background, with a plan to have them while checking at intervals of 5 minutes or so.

The application is registered for location updates in the background (using the "Application updates registers for location updates" for "Required background modes"), and we run a background task that checks the location once, stops location updates, and then uses NSThread sleepForTimeInterval: to (on At the moment, while we are in development) we suspend the task for 10 seconds. Then it checks the location again, stops location updates, pauses for 10 seconds, etc.

It looks like it works as expected ... When the application goes into the background, we get a log / notification with our location update every 10 seconds, and when the application opens again, the logs / notifications stop. However, the problem is that when the application goes back to the background a second time, it seems that the original background task has never been canceled and a new one is being created, so now two tasks are being performed, each of which checks the location for 10 seconds at intervals. If the application is open or sent to the background several times, then for each of them a background task is launched.

I thought about setting a flag to say โ€œwas the application sent to the background at least once?โ€ And only run the task if it was first sent to the background, but this seems to cause additional problems , and (as a relatively new iOS developer) I am curious why background tasks are not canceled when the application comes to the fore.

The file AppDelegate.h contains ...

 @interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate> { UIWindow *window; UINavigationController *navigationController; UIBackgroundTaskIdentifier bgTask; BOOL inBackground; } 

The file AppDelegate.m contains ...

 - (void)applicationDidEnterBackground:(UIApplication *)application { inBackground = YES; bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (inBackground == YES) { NSLog(@"%@", @"Check location..."); [locationManager startUpdatingLocation]; [NSThread sleepForTimeInterval:10]; } [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }); } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. inBackground = NO; [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } 

Location updates work as expected, I just canโ€™t understand why the background tasks are not canceled / terminated when the application comes to the fore. I really wonder if this is not related to NSThread sleepForTimeInterval: but I'm not sure if this is the case, or how to fix it (if that is true). Thanks for any help!

+4
source share
2 answers

I'm sure your bgTask instance bgTask redistributed when the application comes back to the fore, so the value does not contain the identifier you want to kill. Consider storing this identifier in NSUserDefaults or something more permanent and get it later.

+1
source

You do not manage location updates by sleeping and then requesting them. You manage location updates by setting the "location" in the UIBackgroundMode (like you), and then implement the CLLocationManagerDelegate . This has nothing to do with beginBackgroundTaskWithExpirationHandler: This is to request additional time (up to 10 minutes) to complete this operation. You do not have to call it at all to get location updates.

Once you have registered as a location application in UIBackgroundMode , you will automatically receive updates whenever the location changes with the accuracy you specified for your location manager. The system will do all the work for you.


What you describe can damage battery life, because it interferes with the ability of the OS to control multiple location sensors (of which GPS is only one). Tell the OS what you need by setting the correct accuracy (if significant changes are too gross) and let it do its job. Getting a really accurate location from GPS is expensive. You should do a battery test before you consider it cheaper to do every 5 minutes than to leave. The best you can do to conserve energy is to reduce the required accuracy. You can flip it to a rough level, and then when you go to the foreground, move it to a level level. But keep track of where the user every 5 minutes will be expensive. Itโ€™s hard to fix it.

By the way, what you're really trying to do here is to run "something" every 5 minutes. There is no mechanism for this in iOS. You can either request location services or not (and configure it in various ways). You cannot ask, "I want to wake up every five minutes and ... do something." After about 10 minutes, you will be killed if you do not name endBackgroundTask:

For your question why tasks are not canceled, see How to use beginBackgroundTaskWithExpirationHandler for an already running task in iOS . As I said, these "background tasks" are not the tool you want for this problem. He is not completely connected.

+2
source

All Articles