iOS后台报告位置

转自(原文见) :  http://www.mindsizzlers.com/2011/07/ios-background-location/


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.

kground)

-(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 == UIApplicationStateBac

    {
        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.


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.

  • delicious
  • digg
  • facebook
  • reddit
  • stumble
  • twitter
  • rss
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

    Related pages…

    ios background location

    Wordle of the Day

    src="http://wordle-of-the-day.com/widget.cgi?g=320x" width="320" height="280" frameborder="0" scrolling="no" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">

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

    Categories


    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.

    • delicious
    • digg
    • facebook
    • reddit
    • stumble
    • twitter
    • rss
    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

       

       

       






      y 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.

      • delicious
      • digg
      • facebook
      • reddit
      • stumble
      • twitter
      • rss
      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

        Related pages…

        ios background location

        Wordle of the Day

        src="http://wordle-of-the-day.com/widget.cgi?g=320x" width="320" height="280" frameborder="0" scrolling="no" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">

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

        Categories



        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.

        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.

        • delicious
        • digg
        • facebook
        • reddit
        • stumble
        • twitter
        • rss
        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

           

           

           

          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.

          • delicious
          • digg
          • facebook
          • reddit
          • stumble
          • twitter
          • rss
          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

             

             

             

            • 0
              点赞
            • 1
              收藏
              觉得还不错? 一键收藏
            • 0
              评论
            评论
            添加红包

            请填写红包祝福语或标题

            红包个数最小为10个

            红包金额最低5元

            当前余额3.43前往充值 >
            需支付:10.00
            成就一亿技术人!
            领取后你会自动成为博主和红包主的粉丝 规则
            hope_wisdom
            发出的红包
            实付
            使用余额支付
            点击重新获取
            扫码支付
            钱包余额 0

            抵扣说明:

            1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
            2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

            余额充值