Menu

What is iBeacon? An explanation and tutorial for iOS 7

Craig Gilchrist By Craig Gilchrist

At Apple's special event in September 2013 they announced their implementation of a Bluetooth Low Energy (BLE) profile for micro-location and integration of geofencing capabilities into their SDK.

This announcement essentially allows developers to enable a mobile user to navigate and interact with specific regions geofenced by relativey cheap signal transmitters.

This technology, put simply, enables indoor location based functionality and allow a user to trigger events around them on a micro level and without the use of GPS.

We're super-excited about this technology and we've ordered some Roximity iBeacons and some sexy Estimote Beacons and as soon as they've arrived we'll be posting some tutorials once we've had chance to play around with the devices a little more.

Since we've already got a loyalty app in production which would benefit from proximity based marketing we just couldn't wait for our beacons to arrive before we started playing.

What is iBeacon?

Indoor proximity marketing with iBeaconsPut simply, an iBeacon is a low cost, low-energy device which emits a bluetooth signal broadcasting a unique ID. You use an app which is programmed to keep an eye out for this unique ID and then triggers some action when your mobile devices comes into range of a beacon. It works slightly different to NFC in that NFC is designed to read unpowered RFID tags which seemed to be the big thing in 2011 as it was widely adopted in Google's Android 4.0 Ice Cream Sandwich operating system but poor adoption and the fact that NFC range is 20cm vs iBeacon's 50m range means that it's limited to interactions relying on almost contact level proximity such as 'contactless' payment or Android's Beam which allows ad-hoc file sharing by holding two Android devices together.

An iBeacon transmitter is a powered device implementing BLE in Bluetooth 4.0 which was first introduced to the iPhone 4S and iPad 3 and every iOS and OSX device since mid-2012. Estimote Beacons contain a lithium battery that should allow the beacon to broadcast a signal up to 70m for 2 years.

All iOS apps run in the background instead of terminating by default. When the vendor app is first started the app starts monitoring for beacons with a specific unique ID and then when the app is entered into the background or terminated due to memory pressure the operating system steps in and starts monitoring for the beacons on the apps behalf and notifies the app when a beacon enters your proximity.

Put simply, your app starts monitoring for beacons the first time it's started and then can perform an action every time one comes into proximity.

Applications of iBeacon

The applications for iBeacon technology are endless. Retail, home automation and museum exhibitions are hot on the hit list of potential applications. Macy's have recently began a pilot test in their flagship New York & San Francisco stores which shows the technologies marketing and retail potential.

We've come up with our own list of implementations that we'd love to get involved with...

  1. Proximity marketing - this is an obvious choice for iBeacon implementation and one we're already considering for Auntie Anne's loyalty app which will go live later this year. Proximity and personalised marketing is the stuff of movies (like Minority Report).
  2. Home automation - imagine pulling up to your drive and your porch lights coming on. That's not groundbreaking really, we've had movement sensors for years but imagine that, as well as the lights coming, on your bath started running, the lights dimmed and relaxing music started playing.
  3. Museums and exhibits - as well as a personalised audio tour on your phone as your browse between exhibits and gallaries without a predetermined direction the museum curator can be building heatmaps of their most popular exhibits and reorganising galleries based on visitor behaviour.
  4. Venue navigation - freshers week at university would be made a whole lot easier by helping new and terrified students around campus with geofenced navigation.
  5. Conference venues - last year we built the Buy Yorkshire Conference app which featured keynote, exhibitor and map information. Using iBeacon we could implement location aware information such as interactive content with the current speakers talk but only available to those people who are sat in the theatre, not to those walking around the exhibitors outside the theatre. Better still the conference venue could provide their own implementation to all conferences.
  6. Car rental - just before you get on a flight you could order and pay for your car rental then when you arrive at the airport, your car could automatically unlock when you get near to it. This would require a little more computation and extra hardware within the car but the essence is made possible by iBeacon.
  7. Taxi Alert - order a cab through your phone and receive a push notification when they're outside waiting for you.

Tutorial - An iBeacon Treasure Hunt

Download the source code

Because I couldn't wait to start messing around with iBeacons before our Estimote Beacons arrive, I decided that I'd use an iPad as an iBeacon transmitter and an iPhone as a receiver. The simplest example I could think of late last night was a treasure hunt where the iPad acts as the treasure and the iPhone acts as the hunter which tells you when you're getting warmer. If you want to following along with this tutorial the source code is available here to download here.

Creating the project

We're going to use a single code base for both the treasure (transmitter) and the hunter (receiver). The code will determine whether it's running on an iPhone or iPad and configure itself accordingly. With that in mind, fire up XCode and create a universal single view application.

XCode Single View Application Dialog

XCode new project settings dialog

Add required frameworks

Our hunter app is going to speak to us like a salty pirate (kind of), for this we need AVFoundation. For iBeacon we need CoreBluetooth and CoreLocation so go ahead and add all three. The image below shows all the linked frameworks in my project.

XCode Linked Frameworks Dialog

Adding Permissions

Heads up, this is required in iOS8 but not in iOS7 to give the user a helpful message as to why you need their permission

Open your project settings by clicking on the project in the left hand window and ensuring that you have selected the target and not the project. Open the info tab and add a new key to the Custom iOS Target Properties with the following values:

  • Key: NSLocationAlwaysUsageDescription
  • Value: This app needs your location to hunt some treasure.

Prepare your views

For our treasure app (the iPad version) we just need a big image of treasure so I won't go into detail about adding this, this iPad view doesn't have any interactive content so manipulate the Main_iPad.storyboard so that your view will look like this:

Arrrrrgh. Treasure.

The iPhone app (the hunter) needs to be a little more interactive. As you get closer to the treasure the background colour and a label will change to look like this:

iBeacon Treasure Hunter Screens

Again, I'll let you manipulate the view storyboard but essentially we need a single UILabel that's attached to an IBOutlet on the main view controller. Go ahead and add a UILabel to the Main_iPhone.storyboard file and bind it to the only view controller in the project. I've named my label statusLabel as you can see below:

Configuring UI Views in XCode

Configure your view controller header

Jump over to your viewcontroller header file and import AVFoundation, CoreBluetooth and CoreLocation:

#import <AVFoundation/AVFoundation.h>  
#import <CoreBluetooth/CoreBluetooth.h>  
#import <CoreLocation/CoreLocation.h>

Because the iPad (the treasure) needs to know when the bluetooth peripheral is ready before it starts advertising itself as a beacon; our viewcontroller needs to implement the CBPeripheralManagerDelegate, also since our iPhone (the hunter) needs to know when a beacon is near it needs to implement CLLocationManagerDelegate. Go ahead and decorate your controller with these now...

@interface THViewController : UIViewController<CBPeripheralManagerDelegate, CLLocationManagerDelegate>

Configuring the transmitter

iBeacons transmit three values:

  • proximityUUID - a property which identifies the vendor. All beacons by a vendor should use the same ID and realistically the app should only be looking out for one vendor code.
  • major - a numeric property to specify a set of related beacons. This can be used to break down a region or to group beacons
  • minor - the minor number ultimately identifies the actual beacon. For example if you use the major value to identify a city or a particular store in a chain of stores then the minor number would identify the beacon in that store.

Since we've only got one beacon all we really need to care about is the UUID. To generate a UUID I used the uuidgen command line tool in terminal:

UUIDGen Console

Go ahead and do the same and then add two constants to your viewcontroller implementation...

static NSString * uuid = @"4234EE23-34A0-4BF7-993A-FE5574A70762";  
static NSString * treasureId = @"com.eden.treasure";

Now in order to transmit we're going to need three things:

  1. A CLBeaconRegion for advertising ourselves
  2. A CBPeripheralManager to tell us when the bluetooth device on our iPad is ready to use and
  3. An NSDictionary containing our preferences for broadcasting

Add these as properties to the interface in the .m file:

@property CLBeaconRegion * beaconRegion;  
@property CBPeripheralManager * peripheralManager;  
@property NSMutableDictionary * peripheralData;

We're going to branch our logic in the viewDidLoad method of the controller to switch functionality based on whether or not the device is an iPad (treasure) or an iPhone (the hunter). Copy the following viewDidLoad method:

- (void)viewDidLoad  
 {  
   [super viewDidLoad];  
   // Regardless of whether the device is a transmitter or receiver, we need a beacon region.  
   NSUUID * uid = [[NSUUID alloc] initWithUUIDString:uuid];  
   self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uid identifier:treasureId];  
   // When set to YES, the location manager sends beacon notifications when the user turns on the display and the device is already inside the region.  
   [self.beaconRegion setNotifyEntryStateOnDisplay:YES];  
   [self.beaconRegion setNotifyOnEntry:YES];  
   [self.beaconRegion setNotifyOnExit:YES];  
   if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {  
     [self configureTransmitter];  
   }  
   else {  
     [self configureReceiver];  
   }  
 }

What we're doing here is setting up a region regardless of whether or not we're on iPhone or iPad since we'll use the same region in both and then we're configuring the region before branching our configuration code based what's reported by the user interface idiom.

The configureTransmitter code is relatively straightforward:

-(void)configureTransmitter {  
   // The received signal strength indicator (RSSI) value (measured in decibels) for the device. This value represents the measured strength of the beacon from one meter away and is used during ranging. Specify nil to use the default value for the device.  
   NSNumber * power = [NSNumber numberWithInt:-63];  
   self.peripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:power];  
   // Get the global dispatch queue.  
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
   // Create a peripheral manager.  
   self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:queue];  
 }

Here we set a power adjustment before getting the peripheral data from the beacon before setting ourselves as a delegate and then intialising the peripheral manager. We can't start broadcasting ourselves as a beacon until the bluetooth adapter on the iPad is turned on and ready and so we do this in the CBPeripheralManagerDelegate.

Go ahead and implement the only method we need from the CBPeripheralManagerDelegate now:

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {  
   // The peripheral is now active, this means the bluetooth adapter is all good so we can start advertising.  
   if (peripheral.state == CBPeripheralManagerStatePoweredOn) {  
     [self.peripheralManager startAdvertising:self.peripheralData];  
   }  
   else if (peripheral.state == CBPeripheralManagerStatePoweredOff) {  
     NSLog(@"Powered Off");  
     [self.peripheralManager stopAdvertising];  
   }  
 }

All we're doing is waiting for the bluetooth device to be powered on before we start transmitting (or advertising) our region and that's all we need to do.

Configure the receiver

Now we need to configure the receiver but before we do we need a couple more properties. Add the following properties to the interface within the .m file: 

@property CLLocationManager * locationManager;
@property CLProximity previousProximity;

 Now add the configure receiver code:

-(void)configureReceiver {  
   // Location manager.  
   self.locationManager = [[CLLocationManager alloc] init];  
   self.locationManager.delegate = self;  
   [self.locationManager requestAlwaysAuthorization];
   [self.locationManager startMonitoringForRegion:self.beaconRegion];  
   [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];  
 }
Note that the call to requestAlwaysAuthorization is required since iOS 8

All we're doing here is setting up a location manager and monitoring for the region we configured earlier. Now we need to configure what happens when we enter the region, exit a region or when we 'range beacons' which is the event which occurs when we get closer or further away from a beacon. Let's start with entering and exiting a region:

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {  
   // See if we've entered the region.  
   if ([region.identifier isEqualToString:treasureId]) {  
     UILocalNotification * notification = [[UILocalNotification alloc] init];  
     notification.alertBody = @"There be a treasure hiding nearby. Find it me hearties.";  
     notification.soundName = @"arrr.caf";  
     [[UIApplication sharedApplication] presentLocalNotificationNow:notification];  
   }  
 }  
 -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {  
   // See if we've exited a treasure region.  
   if ([region.identifier isEqualToString:treasureId]) {  
     UILocalNotification * notification = [[UILocalNotification alloc] init];  
     notification.alertBody = @"Avast ye bilge rat. We be losing sight of the treasure.";  
     notification.soundName = @"arrr.caf";  
     [[UIApplication sharedApplication] presentLocalNotificationNow:notification];  
   }  
 }

Here we are presenting a local notification whenever we're entering or exiting a region with a salty pirate message. The clever stuff happens in the locationManager:didRangeBeacons:inRegion method of CLLocationManagerDelegate:

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region  
 {  
   if ([beacons count] == 0)  
     return;  
   NSString * message;  
   UIColor * bgColor;  
   CLBeacon * beacon = [beacons firstObject];  
   switch (beacon.proximity) {  
     case CLProximityUnknown:  
       message = @"Come 'ere me buxom beauty. There be no treasure in me vicinity";  
       bgColor = [UIColor blueColor];  
       break;  
     case CLProximityFar:  
       message = @"Shiver me timbers. I be more than a long John away";  
       bgColor = [UIColor colorWithRed:.0f green:.0f blue:230.0f alpha:1.0f];  
       break;  
     case CLProximityNear:  
       message = @"Argh. I be no further than a hornpipe away";  
       bgColor = [UIColor orangeColor];  
       break;  
     case CLProximityImmediate:  
     default:  
       message = @"Smartly does it lass. I be richer than a pig in grog";  
       bgColor = [UIColor redColor];  
       break;  
   }  
   if (beacon.proximity != self.previousProximity) {  
     [self speak:message];  
     [self.statusLabel setText:message];  
     [self.view setBackgroundColor:bgColor];  
     self.previousProximity = beacon.proximity;  
   }  
 }

What we do here is switch on the beacon proximity and prepare a background colour and message based on how close the beacon is. If the proximity has changed since last time then we set the view's background colour, the label text and then we speak the message using an AVSpeechSynthesizer. To do this however we need the speak method.

-(void)speak:(NSString*)message {  
   AVSpeechSynthesizer * synth = [[AVSpeechSynthesizer alloc] init];  
   AVSpeechUtterance * utterance = [[AVSpeechUtterance alloc] initWithString:message];  
   [utterance setRate:AVSpeechUtteranceMaximumSpeechRate *.3f];  
   [utterance setVolume:1.0f];  
   [utterance setPitchMultiplier:0.7f];  
   [utterance setVoice:[AVSpeechSynthesisVoice voiceWithLanguage:@"en-IE"]];  
   [synth speakUtterance:utterance];  
 }

I decided that the en-GB implementation of the AVSpeechSynthesizer could never sound remotely pirate-like. He was far too posh and so I took the Irish voice, lowered the pitch and speed and probably got the closest I could to a pirate using the english speaking voices on the iPhone.

We're almost done. The only thing we've overlooked is the fact that we're not doing anything with the local notifications which get raised when the hunter enters a new beacon region. Head on over to the app delegate and add the following code:

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {  
   UIAlertView * av = [[UIAlertView alloc] initWithTitle:@"Find the treasure"  
                          message:notification.alertBody  
                          delegate:NULL  
                     cancelButtonTitle:@"OK"  
                     otherButtonTitles:nil, nil];  
   [av show];  
 }

Now we're presenting a UIAlertView when the app is running and the user enters a new region.

Now we're done

I hope you've had fun playing with iBeacons. The technology has the potential to revolutionise the way we shop, interact and behave in different geolocation settings and here at Eden we're geared up and ready to start building the most amazing geo-ringfenced solutions for you. If you'd like to talk to us about iBeacon solutions then please get in touch.

Tags

iBeaconiOS

Categories

Tutorials
comments powered by Disqus

We’re a top UK digital agency - wahoo!

By Sophie Hardbattle

We're Eden Agency - one of the UK's top digital agencies.

Read more

An Introduction to Building a SpriteKit-UIKit Hybrid App

By Alan Chung

A guide to help you get started on making an iOS app that seamlessly combines the visual punch of SpriteKit with the practicality of UIKit.

Read more

How to build a material design prototype using Sketch and Pixate - Part Three

By Mike Scamell

Part three of a three-part tutorial on building a material design prototype. This section focuses on adding more detail to the prototype in Pixate.

Read more

We're Hiring - Web Developer Role

By Craig Gilchrist

We are currently seeking a full time full-stack web developer to join the team at our Knaresborough office.

Read more

How to build a material design prototype using Sketch and Pixate - Part Two

By Mike Scamell

Part two of a three-part tutorial on building a material design prototype. This section focuses on creating a interactive login screen in Pixate.

Read more