Episode #95

Fun with iBeacons

15 minutes
Published on November 14, 2013

This video is only available to subscribers. Get access to this video and 572 others.

In this episode we take a look at implementing an iBeacon transmitter and receiver. Using this technology we can detect nearby beacons and range them in order to see how far away they are.

Episode Links

Setting up the location manager

In order to track iBeacons you'll need to use the standard CLLocationManager class:

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

Defining the Region to be Monitored

We need to set a few parameters to describe the beacons we're interested in.

    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_UUID];
    CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
     identifier:@"com.nsscreencast.beaconfun.region"];
    region.notifyOnEntry = YES;
    region.notifyOnExit = YES;
    region.notifyEntryStateOnDisplay = YES;

    [self.locationManager startMonitoringForRegion:region];
    [self.locationManager requestStateForRegion:region];

I've defined my BEACON_UUID at the top of the file. To get your own UUID, you can use [[NSUUID UUID] UUIDString] or just type uuidgen from Terminal.

We make sure that we kick off an initial request for the state of this region (because we might already be inside of it).

Location Manager Delegate Methods

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
    if (state == CLRegionStateInside) {
        CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
        [self.locationManager startRangingBeaconsInRegion:beaconRegion];
    }
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    if ([region isKindOfClass:[CLBeaconRegion class]]) {
        CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
        if ([beaconRegion.identifier isEqualToString:@"com.nsscreencast.beaconfun.region"]) {

            [self.locationManager startRangingBeaconsInRegion:beaconRegion];

        }
    }
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    if ([region isKindOfClass:[CLBeaconRegion class]]) {
        CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
        if ([beaconRegion.identifier isEqualToString:@"com.nsscreencast.beaconfun.region"]) {

            [self.locationManager stopRangingBeaconsInRegion:beaconRegion];

        }
    }
}

Here we start ranging the beacons if we notice that we're close. This triggers more frequent callbacks:

- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    for (CLBeacon *beacon in beacons) {
        NSLog(@"Ranging beacon: %@", beacon.proximityUUID);
        NSLog(@"%@ - %@", beacon.major, beacon.minor);
        NSLog(@"Range: %@", [self stringForProximity:beacon.proximity]);

        [self setColorForProximity:beacon.proximity];
    }
}

And we have a couple of methods to define to finish up the example:

- (void)setColorForProximity:(CLProximity)proximity {
    switch (proximity) {
        case CLProximityUnknown:
            self.view.backgroundColor = [UIColor whiteColor];
            break;

        case CLProximityFar:
            self.view.backgroundColor = [UIColor yellowColor];
            break;

        case CLProximityNear:
            self.view.backgroundColor = [UIColor orangeColor];
            break;

        case CLProximityImmediate:
            self.view.backgroundColor = [UIColor redColor];
            break;

        default:
            break;
    }
}

- (NSString *)stringForProximity:(CLProximity)proximity {
    switch (proximity) {
        case CLProximityUnknown:    return @"Unknown";
        case CLProximityFar:        return @"Far";
        case CLProximityNear:       return @"Near";
        case CLProximityImmediate:  return @"Immediate";
        default:
            return nil;
    }
}

Of course you have to run this on an actual device for it to work.