Others Talk, We Listen.

iOS 7 Tutorial Series: Core Location Beacons

by Christopher Mann on Oct 15, 2013

The existing Core Location APIs already provide developers with an array of tools to enrich the user’s experience by delivering location-specific content in mobile applications.  Since iOS 4, developers have had the ability to define a geographical region using CLRegion and track a user’s movement across its boundaries.  This gives businesses the ability to engage customers when they enter a predefined geographical region on their mobile device.  While this is a useful feature, having regions tied to a specific location is limiting and the process of defining and tracking numerous regions across a large area is cumbersome. 

In iOS 7, Apple introduces the concept of iBeacons: circular, Bluetooth LE fields created by advertising a signal from an iPad, iPhone, or any device with the required Bluetooth profile.  This signal can then be monitored using any iOS device supporting Bluetooth 4.0.  Now regions can be created with one or more beacons in different locations to trigger application events specific to each beacon.  For example, a retail store could have one beacon per department, and the app could display current sale items when you walk into that section of the store.  Arguably the best feature of the new API is that iBeacons also allow monitoring to occur without the need to define a fixed geographical location.  Taxis, food trucks, or other mobile services can now use region monitoring to engage customers even though they do not have fixed coordinates because their beacons move when they do.  To make these advances possible, several changes have been made to the Core Location APIs.

Apple has removed direct use of CLRegion, leaving it as an abstract class and adding two concrete subclasses, CLCircularRegion and CLBeaconRegion, to serve in its place.  The center and radius properties of CLRegion have been deprecated but can now be found in CLCircularRegion, which should now be used when tracking of a specific geographical region is still desired. Previously, whenever a user entered or exited a region a notification would be fired causing the app to launch even if the device was in sleep mode.  Now there are two new properties available in CLRegion, notifyOnEntry, and notifyOnExit, which can be used to specify whether or not to notify the user when they enter or exit a given region.  However, the user may not want to be notified every time they are in the vicinity of your store.  In order to avoid unnecessary notifications there is a third new property notifyEntryStateOnDisplay, specific to CLBeaconRegion, which will notify the user upon entry to a region only if the device’s display is on.

// only notify user if app display is on
region.notifyEntryStateOnDisplay = YES;
region.notifyOnEntry = NO;
region.notifyOnExit = NO;


iBeacons

To instantiate a CLBeaconRegion object, you need to provide a UUID as well as a text identifier to uniquely identify your application.  A unique UUID can be created using the Terminal command uuidgen to generate a 16-bit string.

// instantiate new region
NSUUID *myUUID = [[NSUUID alloc] initWithUUIDString:@"10D39AE7-020E-4467-9CB2-DD36366F899D"];
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:myUUID
                                                            identifier:myCompanyIdentifier];


CLBeaconRegion also provides two optional uint16_t properties, major and minor, that can be set during initialization to customize your region information.  One possible use case would be to use major to be the number of a particular store location while minor could be used to reference a particular department, allowing delivery of customized content specific to each beacon.

To start monitoring for regions create a new CLLocationManager instance and call startMonitoringForRegion:.  Region notifications will be triggered via CLLocationManagerDelegate methods locationManager: didDetermineState:forRegion:, locationManager:didEnterRegion:, or locationManager:didExitRegion: allowing the app to notify the user when they have entered or exited a given region.  In addition to providing entry and exit notifications, CLBeaconRegions support ranging. The distance from a particular beacon can be approximated based on a measure of the signal’s strength to provide further customer interaction when a user not only enters a store, but approaches a specific location within the store, such as the service counter or a specific department.

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
 
    // notify user they have entered the region
    if ([region.identifier isEqualToString:kUniqueRegionIdentifier] 
    	&& !self.didShowEntranceNotifier) {
 
        // Optionally notify user they have entered the region
        self.didShowEntranceNotifier = YES;
 
        // start tracking beacons
        [manager startRangingBeaconsInRegion:self.targetRegion];
    }
}


By checking for the proximity of a given beacon, you can notify the user when they are within the immediate vicinity.  The proximity of a CLBeacon is relative to other beacons in a given region and is subject to interference in any given environment.

- (void)locationManager:(CLLocationManager *)manager
        didRangeBeacons:(NSArray *)beacons
               inRegion:(CLBeaconRegion *)region {
 
    // identify closest beacon in range
    if ([beacons count] > 0) {
        CLBeacon *closestBeacon = beacons[0];
        if (closestBeacon.proximity == CLProximityImmediate) {
            /**
             Provide proximity based information to user.  
             You may choose to do this repeatedly or only once depending on the use case.  
             Optionally use major, minor values here to provide beacon-specific content
             */
            [self fireUpdateNotificationForStatus:@"You are in the immediate vicinity of the Beacon."];
 
        } else if (closestBeacon.proximity == CLProximityNear) {
            // detect other nearby beacons
            // optionally hide previously displayed proximity based information
            [self fireUpdateNotificationForStatus:@"There are Beacons nearby."];
        }
    } else {
        // no beacons in range - signal may have been lost
        // optionally hide previously displayed proximity based information
        [self fireUpdateNotificationForStatus:@"There are currently no Beacons within range."];
    }
}


As noted earlier, any iOS device supporting Bluetooth 4.0 can be used as a beacon.  In order to use an iOS device to advertise its Bluetooth signal, instantiate a new CLBeaconRegion utilizing the UUID previously created along with any optional major and minor values.  You will then need to configure a CBPeripheralManager instance and start advertising from your device.  For more information on Core Bluetooth configuration checkout this sample app in the iOS Developer Library or refer to Apple's documentation on CBPeripheralManager.

// advertise region
CLBeaconRegion *advertisingRegion = [[CLBeaconRegion alloc]
                                     initWithProximityUUID:[CSMAppDelegate appDelegate].myUUID
                                                     major:kMyStoreNumber
                                                     minor:kWeeklySpecialItemNumber
                                                identifier:kUniqueRegionIdentifier];
 
NSDictionary *peripheralData = [advertisingRegion peripheralDataWithMeasuredPower:nil];
 
CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc]
                                          initWithDelegate:self
                                                     queue:dispatch_get_main_queue()];
 
[peripheralManager startAdvertising:peripheralData];


Demo

The included sample application provides a demo of the new iBeacon API using two instances of the application; one running in peripheral mode to serve as the iBeacon and one running in region monitoring mode to listen for advertised regions.  Therefore, you will need two iOS 7 devices that support Bluetooth 4.0.  Before launching the app, be sure to enable Bluetooth on each device.  When the application launches you will be prompted to select which mode you would like to use on the device.

iBeaconDemo Screenshot

To configure the device that will serve as your iBeacon, select “iBeacon”.  This will initialize a CBPeripheralManager instance and listen for changes to the CBPeripheralManagerState.  This will result in an error if Bluetooth is not enabled on the device or if the device does not support running in peripheral mode.  Once state equals CBPeripheralManagerStatePoweredOn, the manager will begin advertising the defined CLBeaconRegion.  Once advertising has been enabled the message “Now advertising iBeacon signal…” will be displayed.

iBeaconDemo Screenshot

To configure the other device for region monitoring simply select the “Region Monitoring” option.  This will initialize a new CLocationManager instance and begin monitoring for the specified CLBeaconRegion.  Once monitoring is enabled the message “Now monitoring for region…” will be displayed.  To begin testing, leave the device configured as an iBeacon stationary and walk to a location outside the range of the Bluetooth signal on the device.  As you walk towards the beacon various notifications will be fired, first indicating you have entered the target region then indicating your proximity to the advertising beacon.  As you walk beyond the range of the beacon, you will also be notified that you have exited the region.  The distance required to trigger each notification will vary depending on the signal strength of the device and interference in the area.  Of course, since iBeacons are inherently mobile, testing can be done by moving both devices towards or away from one another. If you have access to a third device you could also configure a second CLBeaconRegion to monitor for two regions simultaneously.

iBeaconDemo Screenshot

Conclusion

With the release of iOS 7 Apple has introduced several changes to the Core Location APIs that provide a more flexible means for interacting with customers to provide a richer user experience.  By removing the need for stationary CLRegions tied to a specific geographical location the introduction of iBeacons has given Core Location much improved region-monitoring capabilities. Apple has announced plans to release a new Bluetooth profile allowing other manufacturers to create compatible, low-cost Bluetooth LE devices, so you can expect to see increased adoption of this technology throughout the marketplace in the coming year. For more information on this and other Core Location updates in iOS 7, see the What's New in Core Location video from WWDC 2013 or refer to the Core Location Framework Reference.

The source code for the demo app can be found here: Demo App. Please feel free to contact me with any questions at cmann@captechventures.com