Search code examples
objective-cibeaconestimote

Estimote: didRangeBeacons not called when in background?



i was wondering why I don't get the notification if my beacon proximity is Immediate – when the app is in background. In foreground mode, everything works fine.

#import "ESTViewController.h"
#import <ESTBeaconManager.h>

@interface ESTViewController () <ESTBeaconManagerDelegate>

@property (nonatomic, strong) ESTBeaconManager* beaconManager;
@property (nonatomic, strong) ESTBeacon* selectedBeacon;
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;

@end

@implementation ESTViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    /////////////////////////////////////////////////////////////
    // setup Estimote beacon manager

    // craete manager instance
    self.beaconManager = [[ESTBeaconManager alloc] init];
    self.beaconManager.delegate = self;
    self.beaconManager.avoidUnknownStateBeacons = YES;

    // create sample region with major value defined
    ESTBeaconRegion* region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID identifier: @"EstimoteSampleRegion" ];

    NSLog(@"TODO: Update the ESTBeaconRegion with your major / minor number and enable background app refresh in the Settings on your device for the NotificationDemo to work correctly.");

    // start looking for estimote beacons in region
    [self.beaconManager startMonitoringForRegion:region];
    [self.beaconManager startRangingBeaconsInRegion:region];

    [self.beaconManager requestStateForRegion:region];

    // setup view
    self.outputLabel.text = @"Seachring for reagion";

}

-(void)beaconManager:(ESTBeaconManager *)manager
   didDetermineState:(CLRegionState)state
           forRegion:(ESTBeaconRegion *)region
{

    // NSLog(@"Region: %@", region);

    if(state == CLRegionStateInside)
    {
        NSLog(@"State: CLRegionStateInside");

    }
    else
    {
        NSLog(@"State: CLRegionOutside");
    }
}

-(void)beaconManager:(ESTBeaconManager *)manager
     didRangeBeacons:(NSArray *)beacons
            inRegion:(ESTBeaconRegion *)region
{
    if([beacons count] > 0)
    {

        self.selectedBeacon = [beacons firstObject]; // get the closest


        NSString* labelText = [NSString stringWithFormat:
                               @"Major: %i, Minor: %i\nRegion: ",
                               [self.selectedBeacon.major unsignedShortValue],
                               [self.selectedBeacon.minor unsignedShortValue]];

        // calculate and set new y position
        switch (self.selectedBeacon.proximity)
        {
            case CLProximityUnknown:
                labelText = [labelText stringByAppendingString: @"Unknown"];
                break;
            case CLProximityImmediate:
                labelText = [labelText stringByAppendingString: @"Immediate"];

                [self fireNotification];

                break;
            case CLProximityNear:
                labelText = [labelText stringByAppendingString: @"Near"];
                break;
            case CLProximityFar:
                labelText = [labelText stringByAppendingString: @"Far"];
                break;

            default:
                break;
        }

        self.outputLabel.text = labelText;
    }
}


-(void)fireNotification {
    NSLog(@"Fire Notification from background");

    // present local notification
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = @"You are very close to the beacon";
    notification.soundName = UILocalNotificationDefaultSoundName;

    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];

    // Request a server...
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Solution

  • With iOS, ranging for iBeacons generally only works in the foreground. The code that checks for CLProximityImmediate is in a ranging callback method.

    If your app is in the background, it will only receive ranging callbacks for five seconds after entering/exiting a monitored iBeacon region.

    This principle is true for the standard iOS CoreLocation APIs. While you are using the proprietary Estimote SDK, the same limitations also apply since it is a wrapper around the standard APIs.