February 2nd 2016
In the summer of 2013, Apple announced iBeacon, communication protocol on top of Bluetooth Smart technology. It allows developers to create mobile apps aware of location context provided by beacons and it provide apps a whole new level of location awareness. They are actually made by third-party manufacturers that follow the guidelines Apple defined. One of those are iBeacons build by Estimote (http://www.estimote.com) currently most popular on the market, but there are many other such as BlueCats, Kontakt etc. This article will be focused on Estimote IBeacons.
When I encountered a situation where I needed to track employee presence in a company and accordingly change their status to online/offline in an app, I needed to wake up my application even when it was killed by user. That gave me headache, because background execution in iOS has a lot of restrictions. iBeacons were my best solution and salvation. Efficient, fast, and with a small cost. I was able to track if user is in the office, using iBeacon monitoring, and also if user is in range of a specific beacon, using ranging. (screenshot of an application screen showing user status is shown below)
IBeacons work as follows : iOS device can alert apps when you approach or leave a location with an iBeacon. In addition to monitoring location, an app can estimate proximity to an iBeacon. iBeacon uses a Bluetooth low energy signal, which iOS devices detect. For example, Estimote Beacons broadcast tiny packets of data, containing their iBeacon ID and information about signal strength, so that the phone can understand which beacon it hears and how far it is. Every iBeacon ID is 20 bytes long and is divided into three sections:
UUID (16 bytes)
major number (2 bytes)
minor number (2 bytes)
All Estimote Beacons have a default UUID:
UUID, major, and minor values of particular beacons can be changed and it is up to developer how to define them. There cannot, however, be two Estimote Beacons with the same ID. iBeacons can do monitoring (triggering “enter” and “exit” events, which the app can react to when moving in and out of the area) in the background. This feature bring some awesome things that you can do with iBeacons, such as waking up your app when passing some location, detecting enter and exit events and do desired things accordingly. Above all, you do not need any Background Modes enabled for your app to work in the background, which can get your app rejected by Apple during the app review process. The “always” authorization is all that is needed.
There are two main features that IBeacons can do:
Triggering actions on entering/exiting region’s range; works in the foreground, background, and even when the app is killed
Triggering actions based on proximity to a beacon; works only in the foreground.
Of course, you must ask user for permission to use their location. To use iBeacons you first need to do a few things:
Authorization to use Location Services
IBeacon is a part of iOS Location services stack, it’s necessary to ask the user of your app for permission to access their location data as follows: Into “Info.plist” file add a new row with a key : NSLocationAlwaysUsageDescription and a type String, and you can add desired message which will be shown to user when asking permission.
ESTBeaconManager is a central peace to all interactions with iBeacons. All beacons events are delivered to its delegate, so your view controller must conform to the ESTBeaconManagerDelegate protocol. It’s important to instantiate the manager as part of the AppDelegate’s applicaton:didFinishLaunching method, because beacon manager can execute code even when app is killed if we use monitoring.
All you need to do to detect user location is to define area which you want to observe. In case of iBeacon, the area is defined by the range of one or more beacons. Beacon regions are defined by already mentioned, UUID ,minor and major values. More than one iBeacon can have same UUID, which means that we can, for example , trigger some actions when app detects beacons with same UUID. If we want to do something when user is in some specific part of global area than we use major and minor values. For example we can track if user entered some shopping mall, for that, we can use only UUID of beacons. Than we want to detect if user is in some specific department of shopping mall , we use UUID as well as major value of beacons (more than one beacon can have same UUID and major value). In the end, we can detect if user is, in some department, in a shopping mall, in specific shop. For that we use UUID, major and minor values (all three values combined are unique beacon ID, which means that only one beacon can have same set of those values).
When monitoring a region that spans multiple beacons, there will be a single “enter” event when the first matching beacon is detected; and a single “exit” event when none of the matching beacons can be detected anymore. Number of beacons that can be monitored at a same time is 20. Also, exit events can take up to 30 seconds to trigger. To start monitoring in SWIFT:
self.beaconManager.startMonitoringForRegion(CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D")!, identifier: "monitored region")
When user enters or exits region, those events are brought to Beacon Manager didEnterRegion and didExitRegion where you can define actions.
Above I described monitoring, as I mentioned, beacons have another feature: ranging. With monitoring, our app will be notified whenever the user enters and exits the terminal. But if we start ranging for the exact same region, we’ll instead get a full list of matching beacons currently in range—complete with their UUID, major, and minor values. There’s no limit to the number of regions that can be ranged which is different as monitoring that has limit to 20. Also, ranging can only be done in foreground.
Things that you need to do, to use ranging:
Apart from calling requestWhenInUseAuthorization, you’ll also need to rename the key in your "Info.plist" file to NSLocationWhenInUseUsageDescription.
Define your region with UUID, major and minor values
Define your ViewController as ESTBeaconManagerDelegate
Start raging : self.beaconManager.startRangingBeaconsInRegion(self.beaconRegion)
Do stuff when in region: func beaconManager(manager: AnyObject, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion)
Stop ranging: self.beaconManager.stopRangingBeaconsInRegion(self.beaconRegion)
IBeacons have a lot of pros: they have some great features, they are easy to implement, have low energy consumption and with a bit of creativity you can make awesome apps and have wide set of application options. Some disadvantages are safety for user and smaller location precision ,because distance measurement is associated with the transmission of signals, which may be affected by different factors.