0
votes

What I want to do: iPhone is sleeping. In the background location manager is scanning for a beaconRegion. If this region is recognized my app should start beacon ranging to verify the distance to the beacon. The beacon ranging should stop when the region is left.

So here is my code:


-(void)locationManager:(CLLocationManager *)manager
        didEnterRegion:(CLRegion *)region
{
    NSLog(@"********** Beacon Region entered: %@", region);

    self.locationManager.allowsBackgroundLocationUpdates = YES;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [self.locationManager startUpdatingLocation];

    [self doBeaconRanging:(CLBeaconRegion *)region];

}

-(void)locationManager:(CLLocationManager *)manager
       didRangeBeacons:(NSArray<CLBeacon *> *)beacons
              inRegion:(CLBeaconRegion *)region
{
    NSLog(@"locationManager didRangeBeacons inRegion.");
}

-(void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(nonnull NSArray<CLLocation *> *)locations {

    NSLog(@"locationManager didUpdateLocations");
}

-(void)locationManager:(CLLocationManager *)manager
         didExitRegion:(CLRegion *)region
{

    NSLog(@"********** Beacon Region left **********");

    [self.locationManager stopUpdatingLocation];

    NSSet *regions = [self.locationManager monitoredRegions];
    for(CLBeaconRegion *region in regions)
    {
        [self.locationManager stopRangingBeaconsInRegion:region];
    }
}

This works fine when the region if entered while the app is in foreground. didEnterRegion is fired and the beacon ranging starts. Even if I send the app and the iPhone to sleep the beacon ranging goes on and on (just to test, in real app I will stop beacon ranging after approx 3 minutes).

But when didEnterRegion is fired while the iPhone is locked the behaviour is different. Location update and beacon ranging starts, but only for ca. 10 seconds. After 10 seconds the iPhone goes back to sleep and location updates and beacon ranging stops. When I wake up the app the location updates start immediately and the beacon ranging as well. But of course, I do not want to wake up the app. Everything should run in the background without the need to open the app.

If I start location updates when app is in foreground and never stop it, than everything works fine. Location updates coming in all the time even after hours in background. But I think this is no solution due to battery life.

How can I start updating Location when didEnteredRegion is fired while the app is in background?

1

1 Answers

0
votes

By default beacon ranging updates are blocked in the background on iOS except for the first 10 seconds after one of these events:

  1. Transition to the background
  2. Monitoring entry/exit event (e.g. geofence or beacon region enter exit event)
  3. Screen on event (if beacon monitoring is enabled and notifyEntryStateOnDisplay is set to true for the monitored region).

In addition to the above it is possible to extend the amount of time background ranging is allowed after one of these events from 10 seconds to 30 seconds (180 seconds on iOS 12 and earlier) by starting a background task.

Finally, you can extend the 30 seconds to an indefinite time period by additionally declaring a location background mode in Info.plist and using CoreLocation to call startUpdatingLocation. A 3km accuracy on the location update is sufficient to keep ranging going indefinitely without burning battery with GPS.

Be aware that if you do declare background location in the Info.plist, you may have trouble getting AppStore approval unless you are building what appears to be a navigation app. Also be aware that constant background ranging will use significant battery, although less than constant GPS usage.

You can read more about executing these options in my blog post here.