We’ve spent some time playing with iBeacons in the Brooklyn office recently. We noticed pretty quickly the lack of utilities (or even API support) on the Mac desktop for the protocol. To help remedy this, we’ve authored a utility called BeaconScanner.
BeaconScanner provides an easy way to scan for nearby beacons from your Mac. Additionally, the underlying source framework can be used to add iBeacon client support to any other OSX project. Finally, it’s a useful tool for demonstrating how the protocol works. The latest build will also display bluetooth status and whether or not Bluetooth LE is supported.
How to Install It
To install without building from source, first download the prebuilt archive. Double click the zip to extract, and then double click again to run.
Once you start the app it’ll automatically begin scanning for bluetooth devices. Any beacons within range will automatically appear and it will continuously update as long as it remains scanning.
The application requires OSX Mavericks (10.9) and Bluetooth 4.0 .
Note: You’ll also need to make sure you have bluetooth enabled in order to see any beacons.
How to Build It
Building the app requires cocoapods. Once installed, launch Terminal.app and in the project directory, run “pod install”. When it completes, open BeaconScanner.xcworkspace in Xcode. The app should then build and run successfully.
How It Works
The iBeacon protocol is relatively simple. It is a 25 byte payload that is set as the manufacturer data field of a bluetooth LE advertisment. The format of this message is as follows:
In order to receive nearby bluetooth advertisements HGBeaconScanner instantiances a Core Bluetooth Central manager, and assigns it a dedicated dispatch queue:
It then asks the Bluetooth Central Manager to start scanning for peripherals:
The options specify it should should execute a callback everytime it detects any given device. This is important for iBeacons, as their continued detection is the only way to determine if they’re still in range.
In this delegate callback, the beacon manager determines whether or not a detected peripheral is an iBeacon by trying to parse the iBeacon message from the advertisement data dictionary recieved from the peripheral. If it succeeds it sends a HGBeacon object created from the message to its subscribers.
The parsing of the advertisement data dictionary happens inside HGBeacon. It first seperates the manufacturer data from the advertisement dictionary and then attempts verify and parse this data. If it succeeds, it returns a new beacon.
Following are the relevant stanzas where this happens:
Adding Beacon Detection to Your Own Project
To add iBeacon support to your own desktop application (at least until the a proper cocoapod is made available), just copy the following four files into your project:
The beacon scanner will publish the beacons it detects to a ReactiveCocoa signal that it provides for the purpose.
All that’s needed for a client to detect beacons is to subscribe to this signal:
To limit this subscription to just those beacons that are relevant to your application, a filtered signal can be composed from the raw feed, like so:
Note that as long as any given beacon is in range, it will be announced periodically via the signal subscription.
It’s best to use these updates to maintain a list of nearby beacons, and periodically purge from this list those that have not been updated for a certain amount of time (15 seconds seems to work) in order to ensure that only beacons are on and in range are regarded as active.
In the application source, the class HGBeaconViewController provides a good example of how to do this.
An excellent primer is Adam Warski’s post on “How iBeacons work?”.
The “What is the iBeacon Bluetooth Profile?” thread on Stack Overflow is also very informative.
In order to turn your OSX Mavericks box into an iBeacon emitter, see Matthew Robinsons’ BeaconOX.