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.

<span class="co2">// only notify user if app display is on</span>
region.notifyEntryStateOnDisplay <span class="sy0">=</span> <span class="kw2">YES</span>;
region.notifyOnEntry <span class="sy0">=</span> <span class="kw2">NO</span>;
region.notifyOnExit <span class="sy0">=</span> <span class="kw2">NO</span>;

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.

<span class="co2">// instantiate new region</span>
NSUUID <span class="sy0">*</span>myUUID <span class="sy0">=</span> <span class="br0">[</span><span class="br0">[</span>NSUUID alloc<span class="br0">]</span> initWithUUIDString<span class="sy0">:</span><span class="co3">@</span><span class="st0">"10D39AE7-020E-4467-9CB2-DD36366F899D"</span><span class="br0">]</span>;
CLBeaconRegion <span class="sy0">*</span>region <span class="sy0">=</span> <span class="br0">[</span><span class="br0">[</span>CLBeaconRegion alloc<span class="br0">]</span> initWithProximityUUID<span class="sy0">:</span>myUUID
 identifier<span class="sy0">:</span>myCompanyIdentifier<span class="br0">]</span>;


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<span class="sy0">:</span>. Region notifications will be triggered via CLLocationManagerDelegate methods locationManager<span class="sy0">:</span> didDetermineState<span class="sy0">:</span>forRegion<span class="sy0">:</span>, locationManager<span class="sy0">:</span>didEnterRegion<span class="sy0">:</span>, or locationManager<span class="sy0">:</span>didExitRegion<span class="sy0">:</span> 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.

<span class="sy0">-</span> <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>locationManager<span class="sy0">:</span><span class="br0">(</span>CLLocationManager <span class="sy0">*</span><span class="br0">)</span>manager didEnterRegion<span class="sy0">:</span><span class="br0">(</span>CLRegion <span class="sy0">*</span><span class="br0">)</span>region <span class="br0">{</span>
 
 <span class="co2">// notify user they have entered the region</span>
 <span class="kw1">if</span> <span class="br0">(</span><span class="br0">[</span>region.identifier isEqualToString<span class="sy0">:</span>kUniqueRegionIdentifier<span class="br0">]</span> 
 <span class="sy0">&&</span> <span class="sy0">!</span>self.didShowEntranceNotifier<span class="br0">)</span> <span class="br0">{</span>
 
 <span class="co2">// Optionally notify user they have entered the region</span>
 self.didShowEntranceNotifier <span class="sy0">=</span> <span class="kw2">YES</span>;
 
 <span class="co2">// start tracking beacons</span>
 <span class="br0">[</span>manager startRangingBeaconsInRegion<span class="sy0">:</span>self.targetRegion<span class="br0">]</span>;
 <span class="br0">}</span>
<span class="br0">}</span>


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.

<span class="sy0">-</span> <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>locationManager<span class="sy0">:</span><span class="br0">(</span>CLLocationManager <span class="sy0">*</span><span class="br0">)</span>manager
 didRangeBeacons<span class="sy0">:</span><span class="br0">(</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/"><span class="kw5">NSArray</span></a> <span class="sy0">*</span><span class="br0">)</span>beacons
 inRegion<span class="sy0">:</span><span class="br0">(</span>CLBeaconRegion <span class="sy0">*</span><span class="br0">)</span>region <span class="br0">{</span>
 
 <span class="co2">// identify closest beacon in range</span>
 <span class="kw1">if</span> <span class="br0">(</span><span class="br0">[</span>beacons count<span class="br0">]</span> > <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span>
 CLBeacon <span class="sy0">*</span>closestBeacon <span class="sy0">=</span> beacons<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>;
 <span class="kw1">if</span> <span class="br0">(</span>closestBeacon.proximity <span class="sy0">==</span> CLProximityImmediate<span class="br0">)</span> <span class="br0">{</span>
 <span class="coMULTI">/**
 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
 */</span>
 <span class="br0">[</span>self fireUpdateNotificationForStatus<span class="sy0">:</span><span class="co3">@</span><span class="st0">"You are in the immediate vicinity of the Beacon."</span><span class="br0">]</span>;
 
 <span class="br0">}</span> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>closestBeacon.proximity <span class="sy0">==</span> CLProximityNear<span class="br0">)</span> <span class="br0">{</span>
 <span class="co2">// detect other nearby beacons</span>
 <span class="co2">// optionally hide previously displayed proximity based information</span>
 <span class="br0">[</span>self fireUpdateNotificationForStatus<span class="sy0">:</span><span class="co3">@</span><span class="st0">"There are Beacons nearby."</span><span class="br0">]</span>;
 <span class="br0">}</span>
 <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span>
 <span class="co2">// no beacons in range - signal may have been lost</span>
 <span class="co2">// optionally hide previously displayed proximity based information</span>
 <span class="br0">[</span>self fireUpdateNotificationForStatus<span class="sy0">:</span><span class="co3">@</span><span class="st0">"There are currently no Beacons within range."</span><span class="br0">]</span>;
 <span class="br0">}</span>
<span class="br0">}</span>


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.

<span class="co2">// advertise region</span>
CLBeaconRegion <span class="sy0">*</span>advertisingRegion <span class="sy0">=</span> <span class="br0">[</span><span class="br0">[</span>CLBeaconRegion alloc<span class="br0">]</span>
 initWithProximityUUID<span class="sy0">:</span><span class="br0">[</span>CSMAppDelegate appDelegate<span class="br0">]</span>.myUUID
 major<span class="sy0">:</span>kMyStoreNumber
 minor<span class="sy0">:</span>kWeeklySpecialItemNumber
 identifier<span class="sy0">:</span>kUniqueRegionIdentifier<span class="br0">]</span>;
 
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span class="kw5">NSDictionary</span></a> <span class="sy0">*</span>peripheralData <span class="sy0">=</span> <span class="br0">[</span>advertisingRegion peripheralDataWithMeasuredPower<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">]</span>;
 
CBPeripheralManager <span class="sy0">*</span>peripheralManager <span class="sy0">=</span> <span class="br0">[</span><span class="br0">[</span>CBPeripheralManager alloc<span class="br0">]</span>
 initWithDelegate<span class="sy0">:</span>self
 queue<span class="sy0">:</span>dispatch_get_main_queue<span class="br0">(</span><span class="br0">)</span><span class="br0">]</span>;
 
<span class="br0">[</span>peripheralManager startAdvertising<span class="sy0">:</span>peripheralData<span class="br0">]</span>;


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.

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.

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.

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