0

MY QUESTION IS: How can I enable continuous monitoring from the central while the phone is locked (no display turned on) or while its in the background?

First of all, I am using the iBeaconDemo courtesy of Christopher Mann @ https://github.com/csmann/iBeaconDemo and I take no credit for writing this demo, but I am using it to understand iBeacons and Region Monitoring. It is a great demo, but I wish it had background monitoring enabled to show a local notification when you enter the Near range.

I have enabled bluetooth-central, bluetooth-peripheral and locations in my Capabilities (info.plist) file and have set .notifyOnDisplay, notifyOnEntry and notifyOnExit to YES and have found that I get results while the app is in the foreground or on the lock screen (pressing the home button while the phone is locked) but I cannot get it to monitor while it is in the background (phone is unlocked) or while the phone is locked (no display on).

This is my appDelegate's didEnterBackground method (note: this is a different local notification and this one works correctly every time but not the same as the notification I want to be displayed when I enter the region:

    - (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"Application entered background state.");
    [[UIApplication sharedApplication] cancelAllLocalNotifications];

    // create local notification and present it immediately
    UILocalNotification *notification = [self createLocalNotification:@"Bring app back to foreground"];
    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}

Here are the notifications I want to present while in the background, I just need 1 notification to pop up once I enter the region (I put 1 in each for testing purposes):

    - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {

    // identify closest beacon in range
    if ([beacons count] > 0) {
        CLBeacon *closestBeacon = beacons[0];
        if (closestBeacon.proximity == CLProximityImmediate) {
            /**
             Provide proximity based information to user.  You may choose to do this repeatedly
             or only once depending on the use case.  Optionally use major, minor values here to provide beacon-specific content
             */

            [self fireUpdateNotificationForStatus:[NSString stringWithFormat:@"Range: %li \n Beacon Name: %@ \n You are in the immediate vicinity of the Beacon.", (long)closestBeacon.rssi, ((CLBeaconRegion*)region).identifier]];

            [[UIApplication sharedApplication] presentLocalNotificationNow:[self createLocalNotification:@"Immediate LN"]];


        } else if (closestBeacon.proximity == CLProximityNear) {
            // detect other nearby beacons
            // optionally hide previously displayed proximity based information
            [self fireUpdateNotificationForStatus:[NSString stringWithFormat: @"Range: %li \n Beacon Name: %@ \n There are Beacons nearby.", (long)closestBeacon.rssi, ((CLBeaconRegion*)region).identifier]];

            [[UIApplication sharedApplication] presentLocalNotificationNow:[self createLocalNotification:@"Near LN"]];

        } else if (closestBeacon.proximity == CLProximityFar) {

            [self fireUpdateNotificationForStatus:[NSString stringWithFormat:@"Range: %li \n Beacon Name: %@ \n You are far away from the %@th beacon in store %@!", (long)closestBeacon.rssi, ((CLBeaconRegion*)region).identifier, closestBeacon.minor, closestBeacon.major]];

            [[UIApplication sharedApplication] presentLocalNotificationNow:[self createLocalNotification:@"Far LN"]];

        }

    } else {
        // no beacons in range - signal may have been lost
        // optionally hide previously displayed proximity based information
        [self fireUpdateNotificationForStatus:@"There are currently no Beacons within range."];
    }
}

Lastly, here is the fireUpdateNotificationsForStatus method incase this may be useful:

    - (void)fireUpdateNotificationForStatus:(NSString*)status {
    // fire notification to update displayed status
    [[NSNotificationCenter defaultCenter] postNotificationName:kLocationUpdateNotification
                                                        object:Nil
                                                      userInfo:@{@"status" : status}];
}

If there is anything else that would be useful to help out, please feel free to let me know. Thank you for your time!

  • Why do you use `[[UIApplication sharedApplication] cancelAllLocalNotifications];` when the app did enter background? – lagos Nov 14 '13 at 13:35
  • It is mainly for testing purposes. I do that to clear out any old/outstanding notifications that may be left from the last run-through so that I can have a clean notification center when I run the app again. – mantisProxy Nov 18 '13 at 21:52
  • What code are you using to respond to the notification events generated in your `fireUpdateNotificationForStatus:` method? Should that method perhaps be calling `[[UIApplication sharedApplication] presentLocalNotificationNow:notification]` instead? – Yazid Jan 21 '14 at 11:55
  • Well in the didRangeBeacons delegate method, it calls fireUpdateNotificationForStatus method, but it also calls presentLocalNotificationNow method right after it for each case of range (I, N, F). Did I understand what you are asking correctly? – mantisProxy Jan 21 '14 at 20:36

1 Answers1

1

Assuming that the notifications are received by the user (you did test this with logging instead of notifications, right?) and your issue is with backgrounding:

iOs and background scanning are a bit quirky, there a few things you can do:

  • have UiBackgroundModes = location permission set in your app
  • region.notifyEntryStateOnDisplay = YES makes sure that you will receive didRangeBeacons when the screen gets unlocked (you seem to have that)
  • locationManager.pausesLocationUpdatesAutomatically = NO; otherwise ranging is occasionally being shut down when iOs decides the user is no longer moving
  • use startUpdatingLocation as well, with desiredAccuracy = kCLLocationAccuracyThreeKilometers; you will get useless GPS cords too, but it apparently makes iOs not stop beacon ranging.

also see http://airfy.svbtle.com/battery-friendly-indoor-positioning-with-ibeacon

aep
  • 11
  • 1