Question

I have an iBeacons app able to range for beacons while in background or not running. I implemented UILocalNotifications and they work fine, meaning i get a notification when i reach the range of a beacon.

Not having a real beacon i created an app (for another device, let's say an iPad for the next scenario) that acts like 2 different beacons, meaning it can broadcast 2 different signals, same UUID but different Major/Minor values (call this beacon A and B), one at a time obviously. My problem is in this scenario:

  1. Have my iPhone (with iBeacons app closed) in lock screen
  2. Activate my iPad app, broadcasting beacon A
  3. My iPhone reacts showing me a notification
  4. I stop iPad app from broadcasting beacon A, wait 1 second, start broadcasting beacon B
  5. My iPhone DOESN'T react
  6. I stop iPad from broadcasting
  7. A few minutes later (about 2) my iPhone shows me the notification of beacon B

Now what i don't understand is this delay, the first time my iPhone reacts immediately, the second time it takes about 2 minutes to notify me the beacon.

If, after beacon B notification, i re-start broadcasting a beacon (A or B) my iPhone reacts immediately, then for the next time it always waits for 2 minutes.

Why is this happening? I've read some article saying that it's because the bluetooth awakes every 2-4 minutes while the app is in background, so i can get the info not faster than this time. But i don't see much sense in this because whenever i get the second notification the broadcasting of the beacon (B in my scenario) was already stopped, it means that if the bluetooth awakes in that very moment no beacon was in the air! But i get the notification, so it means that in someway my iPhone found it before i stopped the broadcasting.

Is this a problem that can be solved?

EDIT with some code

Here is my viewDidLoad

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Initialize location manager and set ourselves as the delegate and beacons dictionary
    _beacons = [[NSMutableDictionary alloc] init];
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    // Create a NSUUID with the same UUID as the broadcasting beacon
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"6C1AA496-1653-403D-BD1E-7F630AA6F254"];

    // Setup a new region with that UUID and same identifier as the broadcasting beacon
    self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                             identifier:@"testregion"];

    NSLog(@"startMonitoring");
    // Tell location manager to start monitoring for the beacon region
    [self.locationManager startMonitoringForRegion:self.myBeaconRegion];
    [self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion];

    _myBeaconRegion.notifyEntryStateOnDisplay = YES;

    // Check if beacon monitoring is available for this device
    if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]){
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Monitoring not available" message:nil delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil]; [alert show]; return;
    }

}

Now whenever i get a beacon i send a notification, i just wanted to try how it worked so i didn't implemented yet a way to send just 1 notification, it means i get about 9 notification, 1 per sec that's the active time the code can run while in background i suppose (1 second enter region, 9 ranging for beacons)

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region
{
    if([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground){
        UILocalNotification *notification = [[UILocalNotification alloc] init];
        notification.alertBody = @"Found Beacon";
        notification.soundName = @"Default";
        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
    }
}

Actually to be more specific, if i totally close my app from the multitasking view, or just let it in background, as soon as i start broadcasting a beacon i get the notification**S** (1 second delay). Then stopping the broadcasting and re-play the delay becomes in the order of minutes.

Now for a real scenario, where i should have many beacons in the same place, this delay could be a problem, as long as i get the notification when i could be already far away from the beacons itself.

Has my code any problem? I read those articles but i never found a delay of 15 minutes.

EDIT2 after davidgyoung suggestions

I modified my code and as you said using 2 different regions for beacon A and B the delay is always null. I also logged with the piece of code you gave and i discovered this.

  1. Broadcast the beacon of Region_1
  2. Device shows me the notification of Region_1
  3. Stop broadcasting the beacon of Region_1
  4. The logs say i'm still in the region, only after a couple of minutes i get the log "OUTSIDE Region_1", just now i can re-play the broadcasting to get another notification from Region_1.

So i was curious about this and i read and article http://beekn.net/2014/03/apple-ios-7-1-launches-major-ibeacon-improvement/

The author says that from iOS 7.1 the responsiveness of exiting a region is immediate, actually i'm running 7.1 but i also have a couple of minutes delay. Why this? Did you find the same problem in your tests?

Now, i read that a device can listen for no more than 20 regions right?it means that if i have 100 beacons i can set up just 20 regions and divide these 100 in 20 groups, getting no more than 20 notification (assuming these 100 are in the same place, all in the range of my device) ? That could be a problem because will force the user to run the app in the foreground to get all the information (assuming again each of the 100 beacons have a particular and unit role), am i right?

Was it helpful?

Solution

EDIT: This is my first answer before seeing the code.

I cannot explain this behavior based on your description, but I suspect there may be an issue with the setup that is either delaying your local notification or inaccurately reporting the state of beacon region B when the notification is sent.

Two things would help verify/eliminate this possible cause:

  1. Add NSLog statements in your didDetermineState: forRegion: callback like below, then repeat your test reporting the log results.

    // put this in your AppDelegate
    - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
    {
        if(state == CLRegionStateInside) {
            NSLog(@"locationManager didDetermineState INSIDE for %@", region.identifier);
        }
        else if(state == CLRegionStateOutside) {
            NSLog(@"locationManager didDetermineState OUTSIDE for %@", region.identifier);
        }
        else {
            NSLog(@"locationManager didDetermineState OTHER for %@", region.identifier);
        }
    }
    
  2. Post the code that sets up monitoring and issues the notification on detection.

If you have not read this already, you may want to give a quick look to similar tests I have done to measure background detection times:

http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html

http://developer.radiusnetworks.com/2014/03/12/ios7-1-background-detection-times.html

OTHER TIPS

After seeing the code, I think a few issues are going on here:

  1. The code defines only a single region that encompasses BOTH beacon A and beacon B, preventing independent region entry/exit monitoring callbacks, and stopping the phone from getting woken up when switching from transmitting beacon A to beacon B. This is critical, because this means that if you switch from transmitting beacon A to beacon B, iOS will consider itself still in the one region. This can prevent the phone from getting a monitoring event that will wake up the phone in the background.

  2. There is no code in the ranging callback to check which beacon was visible, so it does not seem possible to know for sure which beacon caused the notification. The notification will fire even if the beacon array passed to the ranging callback method is empty (i.e. if no beacons are detected.)

  3. Ranging generally does not work in the background. The only exception is for a few seconds right after entering/exiting a region. I suspect that the two minute delay you report is the time it takes for your iPhone to perform the next background scan for iBeacons (This delay can be 2, 4, or 15 minutes depending on phone state). After that next next scan is performed, a region transition is detected (probably an exit region notification because nothing is transmitting), and ranging starts up for 5 sec firing a notification.

This is all very difficult to test and troubleshoot without directly logging the of the monitoring region callbacks as mentioned in my first answer as well as the ranging callbacks, and logging the identifiers of the beacons detected. Make sure you understand which of these callbacks are firing in order for which beacons, and don't try to troubleshoot too much at once!

In addition to troubleshooting the individual callbacks first, I would also recommend:

  • Changing the code to have one region per beacon for maximum background responsiveness.
  • Putting the detected beacon identifiers in the notification so you know beacon caused the notification to fire.

DavidGYoung is correct. iOS7.1 will invoke your app when terminated upon sensing a beacon region traversal. But,and this is critical, iOS will ONLY invoke a terminated app when you ENTER or EXIT a beacon region, and only if your app has previously registered for location events for that particular beacon region.

In your explanation above, it looks like you are only monitoring for ONE beacon region (you did not specify Major/minor numbers so any beacon with the same UUID will qualify). Unfortunately you created two beacon transmitters with the same UUIDs. So when you started the beacon you got ONE notification (ENTER) but had to wait a couple minutes for another (EXIT). typically I've seen exit notifications about 30 sec after a beacon stops transmitting.

If you want to perform the experiment again, try registering for TWO different beacon regions (declare two regions with diff Major/Minor numbers, or make two diff UUIDs), and then use these two diff values in your beacon transmitter. Should work then. Tom

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top