Charm Down is a Gluon open source project with the purpose of creating a common API for accessing native services on mobile devices when developing JavaFX projects.
We have recently blogged about it, and you can find the code here, and the documentation here.
Now we are adding a new service: a Bluetooth Low Energy API to scan for beacons. For now it is available in the latest snapshot.
BLE and beacons
Bluetooth Low Energy (BLE), a wireless personal area network technology, while providing the same range of communications as classic bluetooth, considerably reduces the power consumption and cost.
Based on this principle, beacons are small wireless devices designed to transmit a simple radio signal continuously, which can be received by nearby smartphones. They transmit only their ID and their signal power, and the smartphone can read those values and estimate the distance to that device.
Among other uses, one of the possible applications for it is for proximity sensing: physical proximity to certain devices equipped with this technology can be estimated based on their radio receiver’s rssi value. This allows for indoor positioning, indoor behavior tracking, in-store interaction between customers and retailers, indoor navigation, and so on.
iBeacons and other beacon protocols
iBeacon is a brand name created by Apple in 2014, a new location technology that lets any phone using iOS7 or newer constantly scan the environment for BLE devices such as beacons. It is a proprietary, closed standard. Other standards like AltBeacon are open. Google launched Eddystone, its open source beacon, in 2015.
Hardware
If you want to use this technology in production, you will need real beacons equipped with BLE, and implementing one of the mentioned protocols. Those are small devices that can be purchased online from different vendors like Estimote, Kontakt or Gimbal. You can find an extensive list of vendors here.
For development, you can simulate a beacon with different apps on Android and iOS.
How to use the Charm Down BLE services
The Charm-Down-Common API provided for beacon detection in Charm Down consists of two classes: `Configuration` and `ScanDetection` and, and one service `BleService`.
Use `Configuration` to set the UUID of the group of devices with that same ID that will be scanned.
When a beacon is detected, an instance of `ScanDetection` is created that provides the UUID, major and minor id, rssi, and proximity (unknown, far, near, immediate).
To use the service, you only need to provide a callback to process the `ScanDetection` object that will be returned from the scan implementation.
The following code snippet does everything that is required to be notified of the presence of beacons with the provided UUID.
BleService bleService = PlatformFactory.getPlatform().getBleService(); Configuration conf = new Configuration("74278BDA-B644-4520-8F0C-720EAF059935"); Consumercallback = (ScanDetection t) -> { Platform.runLater(() -> { System.out.println("Got result: " + t + " with major = " + t.getMajor() + " and minor = " + t.getMinor()); // do some UI operations }); }; // run bleService.startScanning(conf, callback); // stop bleService.stopScanning();
Note that the callback handler is called on a non-JavaFX Thread. Hence, if you want to update user interface components, you have to call `Platform.runLater()` as shown in the code snippet.
Requirements
It is mandatory that Android apps leveraging the `BleService` add these permissions to the AndroidManifest file:
It is mandatory that iOS apps making use of the `BleService` add these keys to the property list file:
NSLocationUsageDescription This app needs location services NSLocationWhenInUseUsageDescription This app needs location services
Beacons Sample
In the Gluon repository you will find Beacons, a new sample implementing a JavaFX application with Gluon Mobile for the UI and BleService functionality. We have a few screenshots further below in this blog post.
The BleService will be included in the next release of Charm-Down. For now, you can use the snapshot version that is available as well.
In the `build.gradle` file, we declare a dependency on the snapshot version of charm-down:
repositories { jcenter() mavenLocal() maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } maven { url 'http://nexus.gluonhq.com/nexus/content/repositories/releases/' } } dependencies { compile 'com.airhacks:afterburner.mfx:1.6.2' compile 'com.gluonhq:charm-down-common:1.0.1-SNAPSHOT' androidRuntime 'com.gluonhq:charm-down-android:1.0.1-SNAPSHOT' desktopRuntime 'com.gluonhq:charm-down-desktop:1.0.1-SNAPSHOT' iosRuntime 'com.gluonhq:charm-down-ios:1.0.1-SNAPSHOT' compile "com.gluonhq:charm-glisten:1.0.0" androidRuntime "com.gluonhq:charm-glisten-android:1.0.0" iosRuntime "com.gluonhq:charm-glisten-ios:1.0.0" desktopRuntime "com.gluonhq:charm-glisten-desktop:1.0.0" }
We created a single home view, with a start and stop button, and some labels to show the beacon values. Also three circles will inform about its proximity (unknown, far, near or immediate).
By default, the app will be scanning for this UUID: “74278BDA-B644-4520-8F0C-720EAF059935”.
The AndroidManifest.xml file in the sample already includes the bluetooth required permissions.
The Default-Info.plist file in the iOS directory in the sample, includes the key `NSLocationWhenInUseUsageDescription` to require location services. You can change its description.
Testing the app
Clone, build and install the app on your device, and if you don’t have a real beacon, install Locate on a different device (Locate for Android, Locate for iOS), set the same UUID this app, and start transmitting. As you can see in the picture below, you can modify the major, minor and power settings, and you will see these new values on the Beacons app.
Notice that if bluetooth is not enabled, a popup will ask you to enable it (both in iOS and Android), and for iOS, the first time you click on the start scanning button, a popup will ask you to enable location services. This can be changed in Settings -> Security -> Location.
Implementation Details
Under the hood, Charm Down creates the implementation for accessing native bluetooth services on Android and iOS, so developers don’t need to worry about this.
Beacon Protocol
Beacons transmit small amounts of data. Beacon IDs consists of a maximum of three values: A universally unique identifier (UUID), a major value and a minor value. Every beacon also transmits information about its signal power.
According to the Bluetooth core specification, a beacon advertises a data package called the Scan Response Data. The scan response is divided into what are called AD structures.
Usually, these will be the 31 bytes sent by the beacon on every transmission, corresponding to two AD structures:
Android
Android API provides a Bluetooth adapter, and a BLE scanner:
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothLeScanner scanner = adapter.getBluetoothLeScanner(); scanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { ScanRecord scanRecord = result.getScanRecord(); // process scanRecord } });
The resulting `ScanRecord` object can be processed following the mentioned bytes structure to obtain a `ScanDetection` instance that can be passed finally to the service callback.
ScanDetection detection = processAD(scanRecord.getBytes()); callback.accept(detection);
iOS
iBeacon is closed protocol, but iOS7+ provides a Location framework for dealing with different location services like GPS and beacons. A `CLBeaconRegion` object defines a type of region that is based on the device’s proximity to a Bluetooth beacon.
While a beacon is in range, the `startRangingBeaconsInRegion` method is used to begin receiving notifications when the relative distance to the beacon changes.
These notifications will be received through the `locationManager:didRangeBeacons:inRegion` method, returning an array of `CLBeacon` with the beacons in range, sorted by proximity. Selecting the first one on that array allows generating a `ScanDetection` instance that can be passed to the service callback.
Conclusions
The functionality we provided in Charm-Down is currently very basic, but it allows you to see how easy it is to use Bluetooth Low Energy devices and detections in a Java Client Application.
There are more usecases for BLE applications, and we encourage developers to create pull requests if you want to contribute to Charm-Down development.
If you have a commercial use case, you can get in touch with us as well.