BuySellAds.com

My book Barcodes with iOS 7 is nearing completion. Buy it now to get early access!
Our DNA is written in Objective-C
Jump

Can you Smell the iBeacon?

iBacon

iBeacons are one of the hot new topics introduced with iOS 7, though I have not seen any actual real life use case for it.

Last week I received my Developer Preview Kit from Estimote and also I have begun to research iBeacons for inclusion in the book I am currently working on. Here are my findings.

There are two words that you should know to understand the difference between the two modes of operation:

  • Monitoring - this refers to a low-power region-monitoring, you get didEnterRegion: and didExitRegion: delegate messages
  • Ranging - this means a higher-power activity where you get the signal strength from individual iBeacons and can estimate distance to them from this

Even before iOS 7 Apple gave us the ability to monitor if a device would enter or exit certain geographic regions, the center stone being CLRegion. This spans a circle around a geolocation and when your device enters or exits this location you can have something happen. Better yet, if you specify in the info.plist that the app should receive background location updates then the system can launch your app on the crossing of the region boundary.

iOS 7 adds CLBeaconRegion which inherits from CLRegion. Here you are defined to be “inside” the region as long as any iBeacon is seen by iOS, however weak its signal might be. During testing this often drove me nuts because iOS claimed me being inside the region even though I had covered all my Estimote beacons in aluminum foil.

An iBeacon is identified by 3 values: proximityUUID, Major and Minor. The first being a UUID and the two latter being two 16 bin integers. You can construct a CLBeaconRegion in 3 levels: only UUID, UUID plus Major, UUID plus Major plus Minor. For example you might want to use one UUID for an entire company and then have Major be the individual stores. Minor could specify individual shelves inside each store.

Let’s Advertise

Normal BTLE peripherals are advertising multiple services, iBeacon is different. iBeacon uses the advertising information itself and has no need for an actual Bluetooth connection because all necessary information is already present in the iBeacon advertisement.

Here’s a bare bones example to start

@implementation ViewController
{
   CBPeripheralManager *_peripheralManager;
   BOOL _isAdvertising;
}
 
- (void)_startAdvertising
{
   NSUUID *estimoteUUID = [[NSUUID alloc] initWithUUIDString:@"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
 
   CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID
                                                                    major:2
                                                                    minor:1
                                                               identifier:@"SimEstimote"];
   NSDictionary *beaconPeripheralData = [region peripheralDataWithMeasuredPower:nil];
 
   [_peripheralManager startAdvertising:beaconPeripheralData];
}
 
- (void)_updateEmitterForDesiredState
{
   if (_peripheralManager.state == CBPeripheralManagerStatePoweredOn)
   {
      // only issue commands when powered on
 
      if (_isAdvertising)
      {
         if (!_peripheralManager.isAdvertising)
         {
            [self _startAdvertising];
         }
      }
      else
      {
         if (_peripheralManager.isAdvertising)
         {
            [_peripheralManager stopAdvertising];
         }
      }
   }
}
 
#pragma mark - CBPeripheralManagerDelegate
 
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
   [self _updateEmitterForDesiredState];
}
 
#pragma mark - Actions
 
- (IBAction)advertisingSwitch:(UISwitch *)sender
{
   _isAdvertising = sender.isOn;
 
   [self _updateEmitterForDesiredState];
}
 
@end

This example would have a UISwitch which toggles the soft-beacon. There are some gotchas in there. First it takes a few milliseconds for the BT system to power on. You should only send the CBPeripheralManager if it is powered on. As soon as it does that you get a peripheralManagerDidUpdateState: delegate callback and if the power is on in there, then you can start to advertise the beacon.

Stopping the iBeacon is much simpler, it only takes a single command. If the CBPeripheralManager is powered off then also all advertisements are stopped. This happens if the app goes in to the background if you don’t tell iOS to keep the BT service running. If I remember correctly then all services are resumed as soon as the app comes back to foreground.

Estimote

It is of no consequence what kind of device you have for performing the function of being an iBeacon. You can make any iOS device (>= iPhone 4S) and any Mac (>= late 2011) sporting a BTLE chip into an iBeacon. Also there are a number of hardware companies which are offering dedicated hardware beacons.

Hardware beacons are ideal for conditions where you don’t want to glue an actual iOS device to the wall. Not everybody can put iPads all around the store for being kiosks. The typical price point of hardware iBeacons is at $99 for 3. This is also what I paid for my 3 Estimote beacons.

Estimote Developer Preview Kit

Estimote did a wonderful job in providing a pleasant unboxing experience. Besides of the 3 differently colored iBeacons you get a button, a sticker, a business card of Estimote’s CEO and Co-Founder Jakub Krzych, and some warning text – spiced up with hand written pieces – informing you that these beacons have still been hand-assembled and might contain firmware bugs.

The first thing you do when receiving the beacons is to download the Estimote demo app which lets you experiment with Monitoring and Ranging as explained above. It also allows you to connect to individual Estimote devices to see their battery level, firmware version and the configured values for UUID, Major and Minor.

At this point I was astonished to learn that Estimote uses a “burned in” UUID. The official statement that this is by design to prevent hackers from hijacking devices and spoofing some other location from these.

The UUID, plainly visible in the app, but also posted on several blogs is:

B9407F30-F5F8-466E-AFF9-25556B57FE6D

This is also the UUID I used in the above example, indeed this creates a simulated Estimote beacon.

Estimote beacons are fully enclosed in rubber and thus there is no physical hardware port, like for a USB plug. Instead all configuration has to happen over Bluetooth and the internal services that Estimote exposes. In a future version of the official Estimote SDK supposedly there will be an encrypted method to hide the UUID for people who still fear for the security of their beacons.

They also would you rather use their wrapper around Core Location and Core Bluetooth instead of using standard iOS methods. Personally I abhor using third-party SDKs for activities that the system provides just as well. The best workaround for potential issue with your neighbor using the same UUID is to use a random Major value to monitor in combination with the UUID. Then when the range is found you would do extra sanity checks – possibly against geo-location – if you are indeed inside your own store.

Monitoring for an iBeacon Range

Provided that you have an Estimote next to you, or created a soft-beacon as shown above, the counter part is to monitor this region. What follows is a minimally viable sample for updating a label and sending a local notification when you cross the region boundary, this goes in the app delegate.

@implementation AppDelegate
{
   CLLocationManager *_locationManager;
   BOOL _isInsideRegion; // flag to prevent duplicate sending of notification
}
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)options
{
   // create a location manager
   _locationManager = [[CLLocationManager alloc] init];
 
   // set delegate, not the angle brackets
   _locationManager.delegate = self;
 
   NSUUID *estimoteUUID = [[NSUUID alloc] initWithUUIDString:@"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
   CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID 
                                                               identifier:@"Estimote Range"];
 
   // launch app when display is turned on and inside region
   region.notifyEntryStateOnDisplay = YES;
 
   if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
   {
      [_locationManager startMonitoringForRegion:region];
 
      // get status update right away for UI
      [_locationManager requestStateForRegion:region];
   }
   else
   {
      NSLog(@"This device does not support monitoring beacon regions");
   }
 
    // Override point for customization after application launch.
    return YES;
}
 
- (void)_sendEnterLocalNotification
{
   if (!_isInsideRegion)
   {
      UILocalNotification *notice = [[UILocalNotification alloc] init];
 
      notice.alertBody = @"Inside Estimote beacon region!";
      notice.alertAction = @"Open";
 
      [[UIApplication sharedApplication] scheduleLocalNotification:notice];
   }
 
   _isInsideRegion = YES;
}
 
- (void)_sendExitLocalNotification
{
   if (_isInsideRegion)
   {
      UILocalNotification *notice = [[UILocalNotification alloc] init];
 
      notice.alertBody = @"Left Estimote beacon region!";
      notice.alertAction = @"Open";
 
      [[UIApplication sharedApplication] scheduleLocalNotification:notice];
   }
 
   _isInsideRegion = NO;
}
 
- (void)_updateUIForState:(CLRegionState)state
{
   ViewController *vc = (ViewController *)self.window.rootViewController;
 
   if (state == CLRegionStateInside)
   {
      vc.label.text = @"Inside";
   }
   else if (state == CLRegionStateOutside)
   {
      vc.label.text = @"Outside";
   }
   else
   {
      vc.label.text = @"Unknown";
   }
}
 
#pragma mark - CLLocationManagerDelegate
 
- (void)locationManager:(CLLocationManager *)manager
	  didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
   // always update UI
   [self _updateUIForState:state];
 
   if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
   {
      // don't send any notifications
      return;
   }
 
   if (state == CLRegionStateInside)
   {
      [self _sendEnterLocalNotification];
   }
   else
   {
      [self _sendExitLocalNotification];
   }
}
 
@end

Essentially you just create a CLBeaconRegion and instruct your instance of CLLocationManager to monitor for it. For some devices beacon monitoring might not be possible, e.g. if they lack a BT4 chip, so you should inquire about isMonitoringAvailableForClass:.

Note that the didDetermineState: is always called after a region boundary crossing as well as following requestStateForRegion:. So you can do all the monitoring in there and/or implement the didEnterRegion: and didExitRegion: just make sure that you don’t bother the user too much.

The rest of the code takes care of sending local push notifications if the app is running in background and preventing sending multiple messages with the same status in succession.

In my tests I would always get the didEnterRegion: message right away after turning on the soft beacon from the first example on my iPad. When I turned the beacon off I would get the didExit message with a delay of 43 seconds. So iOS does some internal filtering that prevents a rapid flip-flop.

In Background

You will find that the above code works nicely while the app is in the foreground but will remain sending/monitoring if it goes into the background, e.g. via pressing the home button.

For monitoring regions in the background you need the “Location updates” background mode enabled in the info.plist. To have the soft beacon persist you need the “Acts as Bluetooth LE accessory”. Xcode provides a nice UI for adding these keys to the info.plist file.

Enabling iBeacon background modes

Changes you make here end up in the UIBackgroundModes key of your info.plist.

Adding the accessory setting also asks the user for authorization of Bluetooth File Sharing. Be aware that the user might deny or turn off this authorization in the device’s privacy settings.

Macs which sport a BT4-compatible chipset are also able to emit a soft-beacon. As of OS X 10.9 CoreBluetooth is also available on the Mac. Late-2011 Macs generally have the chips it takes. The only thing missing is CLBeaconRegion, but if you construct the dictionary for advertising the iBeacon yourself you can work around this. Then the only other thing you need to know is that CoreBluetooth.framework is hidden inside the IOBluetooth.framework on Mac.

Matthew Robinson has created the BeaconOSX sample app that does exactly that.

Competition

At the time of this writing Apple has not yet published the official specification for iBeacon. When I asked the responsible Apple evangelist about this he told me that he’ll let me know when they publish something. So there is still hope that they will do, eventually. In the meantime some smart people still went ahead and reverse-engineered the spec.

Several hardware iBeacons are coming to market and Estimote soon will feel their competition. Other companies I found at a cursory search were:

  • RedBearLab sells a plug in board (aka “shield”) for Arduino 2.0 for $29, they have an iBeacon profile for it.
  • Kontakt.io has beacons running on normal – user-replaceable – batteries. They sell 3 for $99, 5 for $149, 10 for $279.
  • GeoHopper has USB-powered micro-plugs acting as iBeacons: The sell 1 for $39.99, 3 for $89.99, 5 for $192.99.
  • You can also use a Raspberry Pi and Bluetooth LE dongle to roll your own, cost would be around $40 for the device and $10 for the dongle

Of those company which are already shipping Estimote appears to have the best offering.

Having USB-power or user-replacable batteries is much less of a necessity if it turns out that with the lower power consumption of BTLE Estimotes are said to last for 2 years. The waterproof rubber casing and the built-in sticker lets you easily stick them anywhere without having to fear theft or damage.

But the competition does not sleep and as ever more companies are pushing into the hot new field of context and micro-location prices surely will be half or even less next year. We hope that Estimote keep competing on price and reduce it once they are able to churn out boatloads of factory-produced beacons.

The only two negatives I found that personally I think that an custom SDK should not be used as an USP to lock in the customer and that they don’t plan to offer the ability to customize the UUID, however securely. Maybe they will see the light there eventually as well. At this moment these items can easily be worked around and the rest of the “package” is great value.

Conclusion

There is little to prevent us from leveraging the iBeacon technology everywhere to make apps and services aware of the user’s context. If anything then maybe the simple fear that Apple might update their – still secret – iBeacon advertising packets to include other values. But all the hardware devices I mentioned can be updated to adjust the advertised values.

The only problem might be lack of imagination and an inherent slow speed of adoption rate in the sales and corporate markets. iBeacons promise to make it interesting again to enter brick-and-mortar stores. As such any company that still has these is well advised to quickly adopt iBeacons as a means to hook and reel their customers into the physical points of sale.

Small stores can enable an iBeacon running on the Mac or iPad they use for their POS system at no extra cost. This allows Passbook-based vouchers or customer-cards to automatically pop up when next to the cashier’s desk.

Do you know of any innovative uses for iBeacon that you have seen in real life? Or ideas you had during reading this article? Let us know in the comments.


Categories: Recipes

%d bloggers like this: