Starting location updates in background

I am trying to work out how to start updating locations when triggered by a CLRegion in iOS 8 & 9. The use case is that a user gets to a certain predefined starting point (determined by region monitoring) for a regular journey and then the app tracks that journey till it is ended, without need for user interaction. In my testing so far, if I call startUpdatingLocation from within didEnterRegion the updates stop within 10 seconds which I presume is the standard background window for processing a location event. I need those updates to continue until they are explicitly turned off. I have also experimented with switching on SLC followed by standard location but also with no luck. I do however occasionally get some further updates (10 seconds worth) if I touch the home or lock buttons, but this is unreliable. All the examples I have found so far assume that location events are started from the foreground and continued in the background, but in this case I need to have updates started while the app is in background, and to continue in a reliable manner.

Accepted Reply

Let me give an explanation of what is going on.

Everything below assumes two things:

- You have asked and obtained "always" authorization

- You have the 'location' UIBackgroundMode (with all the issues it will bring when crossing the bridge at App Review time Please read app guidelines regarding background modes before committing to use the location background mode)


When you have the above two items sorted out, your app can make the startUpdatingLocation call anytime, foreground or background.


The location updates will start in either case. What changes is, when the startUpdatingLocation call is made while the app is in the foreground (and the 'location' UIBackgroundMode is set), the system holds a background task assertion for your app; meaning your app will not be suspended as long as the location updates are running.


In the case of calling startUpdatingLocation while your app is in the background, CoreLocation still responds by starting the location updates for your app, but the system will no longer hold an assertion for you, and your app will be suspended once the allowed time in the background is spent. The documentation is technically correct - you can start location updates from either state - staying active withuot being suspended is another story.


This time is (currently) is 10 seconds, which is why you think updates stop after 10 seconds. But actually your app is now suspended and can no longer receive the updates. There is a way to extend this duration to (currently) up to 3 minutes by employing beginBackgroundTaskWithExpirationHandler: (Read more about it here: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1


Whether this extended time is enough will depend on your app.


If your goal in trying to wait until later to start location updates is power saving, there are other ways as well.

- if it is suitable for your use case, Significant Location Change service is quite efficient, and a better match to use in conjunction with the standard location service

- you can start location updates when your app is in the foreground and defer location updates while your app is in the background. As your app tracks journeys which would have a start and an end, having location updates running during the journey, while deferring the updates could be suitable for your case.

When the updates are deferred, the system will wake your app when it decides it is power efficient to do so. You can read more about that here: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW14


Also, I suggest you watch the WWDC 2015 presentation "What's new in Core Location" to find out what is coming in iOS 9. There is a new way to get the current location easily which might be of interest to you, and there is an additional step to get background location updates to work. The video is here: https://developer.apple.com/videos/wwdc/2015/?id=714


I am not able to determine from your question whether you are using (or planning to use) the location UIBackgroundMode. The above is assuming you do. If you don't, there will be no standard location updates for your app past the limited time you have in the background. Again, make sure your app is suitable for the use of this mode according to the guidelines to avoid issues at App Review time.

Replies

It would be great (and we'd be grateful!) if someone from Location Engineering could confirm once and for all that standard location updates can't be started from the background (even if you have Always authorization).


To the best of my knowledge, you can only start location updates from the foreground. Maddingly, this isn't clearly documented anywhere that I can find. I think the best confirmation is WWDC 2014 Session 706 (What's New in Core Location) starting at 8:10 ("started in foreground"). However, the speaker is has just been talking about "WhenInUse" authorization, so it isn't completely clear if this also applies to "Always" authorization. It's a pity the API docs for [CLLocationManager startUpdatingLocation] don't address this directly.

My use case and experience were similar to yours. In my case, the app had started location updates in the foreground, but would set up a geofence and stop location updates to conserve power if the user stayed in an area for a few minutes . When exiting the region, starting location updates again would result in ~10 seconds of run time before being suspended. Perhaps there was something I missed in my implementation, but as far as I can tell, this scenario is not supported. It's a shame because it's an opportunity to save a lot of power, but I suppose it's also open to abuse.


By the way, you'll see folks playing games with background tasks and timers, but that's sketchy and unlikely to create the user experience you want. Good luck!


EDIT: I'd forgotten this from the iOS 8 API docs for [CLLocationManager requestAlwaysAuthorization], which is what lead me to try starting location updates from the background in the first place: "When the user grants “Always” authorization to your app, your app can start any of the available location services while your app is running in the foreground or background." However, my experience was the same as yours – it doesn't work that way.

Let me give an explanation of what is going on.

Everything below assumes two things:

- You have asked and obtained "always" authorization

- You have the 'location' UIBackgroundMode (with all the issues it will bring when crossing the bridge at App Review time Please read app guidelines regarding background modes before committing to use the location background mode)


When you have the above two items sorted out, your app can make the startUpdatingLocation call anytime, foreground or background.


The location updates will start in either case. What changes is, when the startUpdatingLocation call is made while the app is in the foreground (and the 'location' UIBackgroundMode is set), the system holds a background task assertion for your app; meaning your app will not be suspended as long as the location updates are running.


In the case of calling startUpdatingLocation while your app is in the background, CoreLocation still responds by starting the location updates for your app, but the system will no longer hold an assertion for you, and your app will be suspended once the allowed time in the background is spent. The documentation is technically correct - you can start location updates from either state - staying active withuot being suspended is another story.


This time is (currently) is 10 seconds, which is why you think updates stop after 10 seconds. But actually your app is now suspended and can no longer receive the updates. There is a way to extend this duration to (currently) up to 3 minutes by employing beginBackgroundTaskWithExpirationHandler: (Read more about it here: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1


Whether this extended time is enough will depend on your app.


If your goal in trying to wait until later to start location updates is power saving, there are other ways as well.

- if it is suitable for your use case, Significant Location Change service is quite efficient, and a better match to use in conjunction with the standard location service

- you can start location updates when your app is in the foreground and defer location updates while your app is in the background. As your app tracks journeys which would have a start and an end, having location updates running during the journey, while deferring the updates could be suitable for your case.

When the updates are deferred, the system will wake your app when it decides it is power efficient to do so. You can read more about that here: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW14


Also, I suggest you watch the WWDC 2015 presentation "What's new in Core Location" to find out what is coming in iOS 9. There is a new way to get the current location easily which might be of interest to you, and there is an additional step to get background location updates to work. The video is here: https://developer.apple.com/videos/wwdc/2015/?id=714


I am not able to determine from your question whether you are using (or planning to use) the location UIBackgroundMode. The above is assuming you do. If you don't, there will be no standard location updates for your app past the limited time you have in the background. Again, make sure your app is suitable for the use of this mode according to the guidelines to avoid issues at App Review time.

Gualtier Maldè,


Thanks very much for responding – especially for the detailed and clear explanation; it's a huge help. Not sure if earth2stu is still out there, but I appreciate it. It validates the solution I settled on for my use case (adjusting deferred update parameters combined with geofencing), and I'll sleep a little better at night.


This is the kind of info that I wish could be included in the CLLocationManager API docs or in a technical note. I understand you want to abstract things and keep the details fuzzy to make it more difficult for "bad" developers from gaming the system, but knowing the determistic behavior saves hours of frustration for the rest of us. So, again, thanks for taking the time.


Finally, in case someone in management ever reads this: Having engineers field questions on these forums is invaluable. It not only helps developers directly, but it fosters a lot of goodwill towards Apple. Historically, it's been very hit or miss getting answers on the dev forums, and I've mailed Tim Cook about that before. Most of my questions over the years have gone unanswered, and it's why the dev forums have typically been the last place I looked. Maybe that's changing? I told Tim I thought there should be dedicated folks that monitor the forums and provide help – especially for the things that only Apple can answer (undocumented behavior, bugs, etc.). I understand that's a very difficult thing to do, but it's something that Apple should tackle. Imagine the applause at WWDC if Tim announced a team had been formed for that purpose. And, if there already is such a team (and for the engineers who help in addition to their regular workload), thanks! Consider this a vote for more folks and resources – and bonuses!

Thanks a lot for elaborating on this!


However, I have one additional question. What is the case with being launched in the background from an Apple Watch message (see "Introducing Watch Connectivity" ~32:00)? E.g. the Apple Watch Runtastic app can launch it's counterpart on iOS to start location updates (even if the iOS app is not running).

As far as I understand this is the only exception where the locationManager will not be killed after 10secs/3mins, right?

"What's new in Core Location" talks about this (~33:45) as well, but only mentions iOS apps to be considered as "In Use" when being launched from a Watch Message. Runtastic however is clearly using "Always" location mode.

Can you elaborate a little on how being launched in the background is being handled in the context of Apple Watch interaction?

Thx!

I have an application with the same use case that was deployed to the store several years ago and now I'm trying to upgrade to 9.2. I'm trying to tamper my frustration, but I don't understand why Apple would do this?? The approach of using region monitoring to detect an exit and then start detailed tracking seems to me to be a good efficient use of system resources. To prevent this forces the application to keep location services on all the time. Also, there are several posts that poin to the WWDC presentation, but that presentation does not provide an insight to solving this issue. I've implemented the request for always authorization and set background to YES. However, still cannot start updates in the background.

Thanks for responding. Could you please explain how "Find My Friends" works? Does it use location manager or any other features with system privilages?

I too would have the very same use case for my app. I would like to start location updates from a region update.

It´s a shame this is not possible :-(


Best

Stephan

An excellent and very informative reply, even after all this time!

thank you for taking the time.