views:

556

answers:

2

This is the section from the CLLocationManager documentation describing the app behavior with startMonitoringSignificantLocationChanges:

If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the application:didFinishLaunchingWithOptions: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application 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 my understanding is that if your app terminates (and I assume if you don't call stopMonitoringSignificantLocationChanges from applicationWillTerminate) you will get woken up with a UIApplicationLaunchOptionsLocationKey parameter to application:didFinishLaunchingWithOptions. At that point you create your CLLocationManager, call startMonitoringSignificantLocationChanges and do your background location processing for a limited time. So I am fine with this bit.

The previous paragraph only talks about what happens when the app is terminated, it doesn't suggest what you do when the application is suspended. The documentation for didFinishLaunchingWithOptions says:

The application tracks location updates in the background, was purged, and has now been relaunched. In this case, the dictionary contains a key indicating that the application was relaunched because of a new location event.

Suggesting that you will only receive this call when your app is launched (because of a location change) after you have been terminated.

However the paragraph on the Significant Change Service in the Location Awareness Programming Guide has the following to say:

If you leave this service running and your application is subsequently suspended or terminated, the service automatically wakes up your application when new location data arrives. At wake-up time, your application is put into the background and given a small amount of time to process the location data. Because your application is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your application may be terminated.

This suggests you are woken up with location data if your app has been suspended, but fails to mention how you are woken up:

In the process of writing this up, I think I may have just answered my own question, but it would be great to have my understanding of this confirmed by someone more knowledgeable.

+2  A: 

My understanding is as follows (I'm in the process of writing an application that relies on this API, but haven't completed this component enough to start testing):

  1. Your application is run for the first time, you register to startMonitoringSignificantLocationChanges, and provide a callback function. While your application is running, it will call that callback whenever it receives a significant change.
  2. If your application is put to the background, UIApplication will receive applicationWillResignActive, followed by applicationDidEnterBackground.
  3. If your application is killed while it is suspended in the background, you will not be notified; however, if your application is killed while it is running (foreground or background to my knowledge), you will get a moment with applicationWillTerminate. You cannot request extra background time from this function.
  4. Despite being killed in the background, the OS will relaunch your application. If your application is simply launched by the OS for a change, you will get a call to application didFinishLaunchingWithOptions:

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
    

    will help you determine if you've come back from a background location change.

  5. If, instead, you were currently running in the background, and your app is manually relaunched by the user, you will receive an applicationWillEnterForeground followed by applicationDidBecomeActive.
  6. Regardless of how it happened, when your application is relaunched (unless it was still running in the background as a result of a background task and said task had started monitoring changes), you need to explicitly tell it to startMonitoringSignificantLocationChanges again because the callback is no longer attached after "freeze drying." And yes, you just need to implement code in didUpdateToLocation once you've re-attached a location handler of some kind once coming back from the suspended state.

This is what I'm going on with my code development right now. As I mentioned before, I'm not quite ready to test this on a device so I can't tell if I've interpreted everything correctly, so commenters, please feel free to correct me (though I've done substantial reading on the topic).

Oh, and if by some stroke of bad luck, you release an app that does what I want mine to do, I might cry :)

Good luck!

Tegeril
@Tegeril +1 Thanks for the answer. I was starting to hear crickets on this one. :) I am surprised that apps started from being suspended need to re-call startMonitoringSignificantLocationChanges. Do you have a link to the doco where this is described? My understanding was that being loaded from a suspended state will instantiate all your objects as they were when the app was suspended. So I would expect the significant change request to be in effect.
Cannonade
You might be talking about this? "Upon relaunch, you must still configure a location manager object and call this method to continue receiving location events" But I think this is referring to the case where you app launched from a terminated state (by a location event). This is basically the root of my question, 'what happens for the suspended case?'.
Cannonade
Morgan Grainger on the Dev forums suggested this: "You need to create a CLLocationManager, set a delegate, and call startMonitoringSignificantLocationChanges when your application is launched, or else Core Location will have nowhere to deliver the updates." in the context of restarting an application regardless of from a terminated or suspended state. From "app was relaunched after startMonitoringSignificantLocationChanges and now what?"
Tegeril
I agree that this could still be vague even in the context of that forum post (the poster was discussing waking from background, but Morgan used the more general restarting of an application). I still think you need to call to monitor again when your application relaunches if you want to work with the significant changes function. If you want to instead launch a background task and update with the standard location service and GPS functionality, that is an alternative option. I don't believe you need to reregister on each launch with significant changes in order to be launched again though.
Tegeril
@Tegeril I guess it depends on how you interpret "relaunched". To me this implies from a terminated state. The statement about Core Location not knowing where to deliver updates makes perfect sense to me in that context. But when you are launched from a suspended state it will thaw out a CCLocationManager object which is hooked up to core location already (like every other object that is thawed out, it should just work). Sounds like I need to try this out :P. I'll let you know what I find out. Thanks again for your answer.
Cannonade
Hopefully one of us will get this to work :D
Tegeril
@Tegeril Heh :) Hopefully. Might be time to go on a train ride to test this out. Debugging while walking around is tricky.
Cannonade
Yeah, most of the discussion I read about testing this involved coercing someone into driving around for an hour while the developer sat in the passenger seat with the phone and a laptop. Not exactly ideal!
Tegeril
@Tegeril Yep. This is the one piece of the documentation that should be totally clear. Testing this stuff is tricky. I tried debugging on the train this morning with the app suspended and didn't get any callbacks. I am not sure if I am doing something wrong or if I was just attached to one cell for the entire time. I have to test the same area with the app running to check.
Cannonade
@Tegeril Thanks again for your answer. Seem my answer for details on how this stuff works for suspended apps. Good luck with your project.
Cannonade
I'm glad something definitive came out of this, should help me in the future :)
Tegeril
+3  A: 

Since I asked this question, I have done a fair bit of testing (mostly on the train between home and work) and have confirmed that the behaviour for suspended apps is as I suspected at the end of the question.

That is, your suspended app is woken up, you don't receive any callbacks on your app delegate, instead you receive your location updates through your existing CLLocationManagerDelegate. You can detect that you are running the background by checking the applicationState, and do limited work for the case where you are woken from a suspended state to do location processing.

[UIApplication sharedApplication].applicationState == UIApplicationStateBackground

I came to this conclusion with a location test harness that you are welcome to download and try out. It is a pretty simple app that allows you to turn on significant change and gps change APIs through the UI and log all the responses that you get back.

N.B. Point six in the previous answer is not correct. Freeze dried suspended apps do receive CLLocationManagerDelegate callbacks when they are woken up from a suspended state.

Cannonade
Struck out #6 in my answer so as not to confuse people.
Tegeril
Ah cool ... Thanks @Tegeril :)
Cannonade