Categorized | iPhone Development

Successful iOS Background Location reporting

We’re working on a location product right now and one of the little challenges along the way has been how to report background location updates back to our servers.

First, some basics.

We’re going to be using the Significant Location Changes feature introduced with iOS 4 as this is the recommended way of tracking the approximate device location in a low power way. As always, the Apple documentation is excellent and is worth reading so you are aware of the detail.

Note the really key features here;

a) If the application is suspended when an update occurs, the system wakes it up in the background to handle the update.

b) If the application starts this service and is then terminated, the system relaunches the application automatically when a new location becomes available.

That’s just perfect, so what we can now do is turn on significant location updates when the user hits the home key and we can let the system wake us up when needed.

-(void) applicationDidEnterBackground:(UIApplication *) application
{
    // You will also want to check if the user would like background location
    // tracking and check that you are on a device that supports this feature.
    // Also you will want to see if location services are enabled at all.
    // All this code is stripped back to the bare bones to show the structure
    // of what is needed.
 
       [locationManager startMonitoringSignificantLocationChanges];
}

Then to perhaps switch to higher accuracy when the application is started up, use;

-(void) applicationDidBecomeActive:(UIApplication *) application
{
       [locationManager stopMonitoringSignificantLocationChanges];
       [locationManager startUpdatingLocation];
}

Next you’ll likely want to change your location manager delegate to handle background location updates.

-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    BOOL isInBackground = NO;
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
    {
        isInBackground = YES;
    }
 
    // Handle location updates as normal, code omitted for brevity.
    // The omitted code should determine whether to reject the location update for being too
    // old, too close to the previous one, too inaccurate and so forth according to your own
    // application design.
 
    if (isInBackground)
    {
        [self sendBackgroundLocationToServer:newLocation];
    }
    else
    {
        // ...
    }
}

OK, so now to the crux of it all. If we are running in the background, we can’t just use the network as we would normally. In background mode the iOS controls very strictly what is allowed, and for how long it is allowed, so if we were just to send the location to our server as normal, we will find this will be highly unreliable. It may work sometimes, it may not, and you will have no control over what is going on.

We can however TELL the operating system in advance that we are doing a background task that should be allowed to run to completion. By doing this, we can ensure that our network activity is given enough time to complete and so the remote server will get the location updates OK.

-(void) sendBackgroundLocationToServer:(CLLocation *)location
{
    // REMEMBER. We are running in the background if this is being executed.
    // We can't assume normal network access.
    // bgTask is defined as an instance variable of type UIBackgroundTaskIdentifier
 
    // Note that the expiration handler block simply ends the task. It is important that we always
    // end tasks that we have started.
 
    bgTask = [[UIApplication sharedApplication]
               beginBackgroundTaskWithExpirationHandler:
               ^{
                   [[UIApplication sharedApplication} endBackgroundTask:bgTask];
                }];
 
    // ANY CODE WE PUT HERE IS OUR BACKGROUND TASK
 
    // For example, I can do a series of SYNCHRONOUS network methods (we're in the background, there is
    // no UI to block so synchronous is the correct approach here).
 
    // ...
 
    // AFTER ALL THE UPDATES, close the task
 
    if (bgTask != UIBackgroundTaskInvalid)
    {
        [[UIApplication sharedApplication} endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
}

The key to this whole process is the use of background tasks to ensure that our synchronous network activity is given enough time to complete. This lets us update a couch database for example where we might need to make 1 network call to get the current document revision and then a second network call to actually PUT the new data.

Share this:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • MySpace
  • StumbleUpon
  • Twitter
  • Yahoo! Buzz

This post was written by:

- who has written 22 posts on Mindsizzlers.


Contact the author

4 Responses to “Successful iOS Background Location reporting”

  1. Saurabh says:

    Excellent post Roger!!!! I am trying to do a similar thing for my own product. I have couple of queries. Is it possible to do a significant location update only when app is closed and normal GPS when app is in foreground or background ???? What i am doing is

    - (void)applicationWillTerminate:(UIApplication *)application {
    [locationManager startMonitoringSignificantLocationChanges];
    }

    and when the app opens i do
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // initialize location manager

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey] ) {
    [locationManager startMonitoringSignificantLocationChanges];
    }

    else{
    [locationManager startUpdatingLocation];

    }

    return YES;
    }

    Also i use UIBackgroundModes locations in plist so location updates keep working as not when app is minimized.

    Any thoughts on this?

  2. Roger says:

    Be careful of running location updates while in the background, that does eat battery power and your users probably won’t thank you for it unless you are delivering a hyper useful service.

    That said, try it and see – that’s always the best way of testing these ideas out. I’d have thought you would be fine, but I haven’t looked in detail.

  3. Mike says:

    Im running significant location changes in the background however the gps icon remains on constantly even when app is background. Is there a solution around this?

  4. Roger says:

    Hi Mike,

    That is correct, the location services icon will remain on if you have background services enabled. It is however a mistake to think it is the “gps icon” – the arrow icon has nothing to do with GPS per se and simply means that location services are active.

    Unfortunately a lot of users think it does mean the GPS is on and draining their battery … and the fact that they are wrong doesn’t really help us developers when using background location services!

    Sadly this is the way the location services are designed by Apple. Perhaps in a future OS release they will make the icon sufficiently different for background use that the users will also pick up on this.

    Until then … all we can do is try to inform them in the application.

Trackbacks/Pingbacks


Leave a Reply

Advert

For more information about our services…

Contact Us

Wordle of the Day

Image from software at http://wordle.net
Data by Web Trends Now

Categories