5

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).

Tys
  • 95
  • 1
  • 8

3 Answers3

4

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];
}
Onnmir
  • 1,030
  • 14
  • 17
0

calculate the value in meter according to user current location with starting point and ending point of beacon that should be inside beacon complete radios, then called didEnterRegionto forcefully or do whatever operation you want to do.

Ashwinkumar Mangrulkar
  • 2,956
  • 3
  • 15
  • 17
  • This answer has nothing to do with what OP asked, which was about iBeacon region monitoring. Even if it's not iBeacon, you should use region monitoring instead of calculating the distance manually. – superarts.org Nov 06 '15 at 03:02
0

Try inserting this line after startMonitoringForeRegion:: [self.locationManager requestStateForRegion:region];.

cojoj
  • 6,405
  • 4
  • 30
  • 52
  • So @Tys it's very strange because your code seems to be fine. I've worked with Estimote Beacons and they've worked well. Why aren't you using their [SDK](https://github.com/Estimote/iOS-SDK)? – cojoj Jun 11 '14 at 06:34
  • I have am using their SDK in other parts - I just thought I'd show the native code for this question so it wasn't specific to Estimote SDK. Don't get me wrong, the beacons work fine. I would just like to get a didEnterRegion callback when I start the app whilst already inside the region :) – Tys Jun 11 '14 at 23:19
  • The solution I wrote was pointed in iBeacons tutorial and it matched your description. I don't know what's wrong... And I guess Estimote guys won't help you as they provide their own SDK. – cojoj Jun 12 '14 at 07:22