Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iBeacon - didEnterRegion not being called when app starts in region

I have made an app that registers beacon regions and starts monitoring these regions using CLLocationManager

CLLocationManager *manager = [[CLLocationManager alloc] init];
manager.delegate = self;

CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID major:12445 identifier:@"id"];
region.notifyEntryStateOnDisplay = YES;
region.notifyOnEntry = YES;
[manager startMonitoringForRegion:region];

This works great when I walk far enough from a beacon and walk back into range. However I would also like the delegate method didEnterRegionto fire if I start the app already in range of the beacon region, not just when I come back into the boundary. Is there an easy way to achieve this? Or a way to make the CLLocationManager think we have left the beacon range?

Another post said that setting region.notifyEntryStateOnDisplay = YES; and pressing the hold button would do this - but I haven't got this working (iOS 7.1, iPhone 5S).

like image 804
Tys Avatar asked Oct 21 '22 07:10

Tys


1 Answers

From apple's documentation:

Monitoring of a geographical region begins immediately after registration for authorized apps. However, don’t expect to receive an event right away, because only boundary crossings generate an event. In particular, if the user’s location is already inside the region at registration time, the location manager doesn’t automatically generate an event. Instead, your app must wait for the user to cross the region boundary before an event is generated and sent to the delegate. To check whether the user is already inside the boundary of a region, use the requestStateForRegion: method of the CLLocationManager class.

So I ended up doing this:

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) NSDictionary *regionDictionary;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // setup regions in case you have multiple regions
    self.regionDictionary = @{@"com.test" : @"2FAE2A83-1634-443B-8A0C-56704F81A181"};

    // setup location manager
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationManager requestAlwaysAuthorization];
    }

    [self.locationManager startUpdatingLocation];

    //start monitoring for all regions
    for (NSString *key in self.regionDictionary.allKeys) {
        CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[key]] identifier:key];
        [self.locationManager startMonitoringForRegion:beaconRegion];
    }
}

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region {
    if (region.identifier.length != 0) {
        CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[region.identifier]] identifier:region.identifier];
        [self.locationManager startRangingBeaconsInRegion:beaconRegion];
    }
}

- (void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region {
    if (region.identifier.length != 0) {
        CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[region.identifier]] identifier:region.identifier];
        [self.locationManager stopRangingBeaconsInRegion:beaconRegion];
    }
}

- (void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region {
    // Beacon found!
    CLBeacon *foundBeacon = [beacons firstObject];
    NSLog(@"UUID:%@; major:%@; minor:%@;", foundBeacon.proximityUUID.UUIDString, foundBeacon.major, foundBeacon.minor);
 }

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
    if ([region isKindOfClass:[CLBeaconRegion class]] && state == CLRegionStateInside) {
        [self locationManager:manager didEnterRegion:region];
    }
}

- (void)locationManager:(CLLocationManager *) manager didStartMonitoringForRegion:(CLRegion *) region {
    [manager requestStateForRegion:region];
}
like image 158
Onnmir Avatar answered Oct 27 '22 17:10

Onnmir