An introduction to iBeacons
A little while ago I did a project where we examined the use of iBeacons in public transportation. Together with the guys from Enigma Consulting, we made a demo to show what was possible and what not. In this blogpost I will show you some code examples that will hopefully get you started using iBeacons.
With the announcement of iOS 7 Apple also introduced us to iBeacons. iBeacons are little bluetooth devices that can be used for proximity or advertisement purposes. The beacon broadcasts a small package of data that consists of a major and a minor value. The major value is used to indicate that a specific beacon belongs to a group of iBeacons. The minor value specifies a single beacon. Using these two values a device can react to the received packages. For example: a museum puts an iBeacon next to a painting. When a visitor comes close to the painting his iPhone will react to the signal that is being transmitted by the beacon. The iPhone can look up the major and minor value in a by the developer defined set of data and shows a description of the painting.
To get started you’ll first need some iBeacons. For the demo we used beacons from Kontakt. They are easy to configure and easy to use. Of course there are a lot more companies that produce iBeacons. We used four iBeacons for this project. Each beacon stood for a different action in the public transport: entering a train station, entering a train, leaving a train and checking in on a bus.
Apple has defined three kind of proximities that a beacon can have: Immediate, near and far. For entering the station we used the proximity far, for entering and leaving a train we used near and for checking in on a bus we used immediate. When the user walked to the next beacon a different image was shown to represent a different action. Below you’ll find an image of the flow of the app.
Now let’s talk some code!
First of all your class has to implement the CLLocationManagerDelegate and its functions. The iBeacons are discovered by creating a CLBeaconRegion. The CLBeaconRegion is initialised with the major value of the beacons that you want to discover. To do this I created the following function:
- (void)initRegion { self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"4A8BE066-324E-4F44-81AF-DF02D0C5B467"]; self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"nl.your.identifier"]; [self.locationManager startMonitoringForRegion:self.beaconRegion]; //[self.locationManager startRangingBeaconsInRegion:self.beaconRegion]; }
We create an UUID that is used to scan for beacons with that value as major. We then create a CLBeaconRegion and tell it to monitor for the given UUID. As you can see I commented out line 11. I used this line as a bit of a cheat. When you’re in a small environment the didEnterRegion function of the CLLocationManagerDelegate will not be triggered because you’re already in the region. To prevent this you can call startRangingBeaconsInRegion which ensures that your beacons are being found!
To handle the behaviour of the detected beacons I used the following two functions:
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region { for(CLBeacon *beacon in beacons){ [self actionForBeacon:beacon]; } }
The function actionForBeacon contains all the logic to handle what output is shown to the user. That function looked something like this:
-(void) actionForBeacon:(CLBeacon *)beacon{ UIImage *image; if ([beacon.minor isEqualToNumber:[NSNumber numberWithInt:1]]) { if(beacon.proximity <= CLProximityFar){ image = [UIImage imageNamed:@"image1"]; [self.imageView setImage:image]; } } }
This function checks if the beacon is the one we’re looking for. If it is also in the right range a new image will be shown. A similar piece of code is used for every beacon that needs to be detected.
Lessons learned
One of the problems we’ve encountered is that it’s very hard to determine proximity with just one beacon per location. The proximity was constantly fluctuating, sometimes a beacon was detected to soon and other times it was detected to late. This can be prevented by using multiple iBeacons. In an ideal set-up you should have three beacons per location so you can use triangulation.
Another problem was that the demo could only be shown when the beacons were nearby. To cover this we build an “offline” functionality in the app so the users could swipe their way through the demo instead of walking.
I had a fun time discovering iBeacons and the possibilities are endless. If you want to know more about iBeacons there is a training coming up by Adrian Kosmaczewski. Also, a free GOTO night will be held in Amsterdam in September.