Quote of the Day

more Quotes

Categories

Get notified of new posts

Buy me coffee

How to detect iBeacons in a NativeScript-Angular app.

Published May 4, 2020 in Mobile development - 1 Comment

At my workplace, we constantly think about ways to improve the user’s experience. One of the things I am working on is enabling our mobile app to aware of the user’s presence when the user come within proximity of certain rooms at our premise and automatically check the user in. For this check-in feature, I found a NativeScript plugin to detect iBeacons using my android phone. In this post, I am going to show you some codes in a sample NativeScript-Angular app to scan for iBeacons.

What is a Bluetooth Low Energy (BLE) beacon?

Prior to Bluetooth 4.0, communications via Bluetooth had always been two ways, which means a device can both emit and receive bluetooth signals. For instance, in our daily lives, we use Bluetooth when we stream music wirelessly from smartphones to Bluetooth headsets, or connect the phones to cars’ stereo systems. In 2010, Bluetooth 4.0 came out and with it, one way communication using low energy is possible and open up innovative use cases such as proximity detection, asset tracking and indoor wayfinding.

A BLE beacon is a little device that constantly emit signals using Bluetooth Low Energy (BLE). You may find them in a variety of form factors, in large retail stores, and embedded in other devices such as WIFI access points and inside smartphones. A battery-powered beacon may last several years, depending on different factors such as configuration, battery type, and manufacture. For instance, I got a development kit of beacons from Estimote two years ago, and as of today, each of those beacons still have 70% of juice left . The more frequent the advertising interval and/or the stronger the signal strength, the more energy the beacon consumes.

What is iBeacon?

Packets of data from BLE beacons along are not helpful if we don’t understand what the data mean. However, it would be hard for developers if manufacturers come up with their own ways of encoding data into BLE beacons. It just makes sense that Apple came up with a standard way to allow a beacon to provide contextual information by assigning the beacon with hierarchy ids which are uuid, major, mior and tx power.

UUID: 16-bytes string for identifying a set of beacons that belong to a large group.

Major: 2-byte string for identifying a set of beacons that belong to a subset of beacons within the large group which is identifiable by the UUID.

Minor: 2-byte string for identifying an individual beacon beacon within a group identifiable by the major id.

Tx power: The signal strength emitting from a beacon 1 meter away from its location.

iBeacon has become a protocol which both Android and iOS support. As a side note, Eddystone is another protocol developed by Google for communicating using BLE. An Eddystone compatible beacon transmits data in a different format than iBeacon. However, in this post, we are not going to discuss about Eddystone.

Detect iBeacon in a NativeScript-with-angular app.

Both iOS and Android SDKs natively support scanning for iBeacons. For NativeScript, you can use a plugin or write your own. Fortunately, I found an existing plugin, the iBeacon plugin by demetrio812 which works and that is what I’m using.

NativeScript iBeacon plugin

If you head to the web page of the plugin, you can see instructions for installing and using it in your NativeScript application. For the most part, the document provides good enough info to get started. I was able to quickly prototype a sample NativeScript-Angular project and use the plugin to scan for iBeacons. Below I show the sample codes I have in my app.component:

import { Component, OnInit, OnDestroy } from "@angular/core";
import { NativescriptIbeacon } from 'nativescript-ibeacon';
import { BeaconLocationOptions, BeaconLocationOptionsIOSAuthType,
    BeaconLocationOptionsAndroidAuthType, BeaconRegion, Beacon } from 'nativescript-ibeacon/nativescript-ibeacon.common';

@Component({
    selector: "ns-app",
    templateUrl: "./app.component.html"
})
export class AppComponent implements OnInit, OnDestroy {

    private _nativescriptIbeacon;
    private _region;

    constructor () {
        var myIbeacon = {
            id: "My iBeacon in conference room of Office A ",
            proximityUUID: "B9407F30-F5F8-466E-AFF9-25556B57FE6D",
            major: 17744,
            minor: 28116
        }
        this._region = new BeaconRegion(myIbeacon.id, myIbeacon.proximityUUID, myIbeacon.major, myIbeacon.minor);

        let options: BeaconLocationOptions = {
            iOSAuthorisationType: BeaconLocationOptionsIOSAuthType.Always,
            androidAuthorisationType: BeaconLocationOptionsAndroidAuthType.Fine,
            androidAuthorisationDescription: "Location permission needed"
        };

        this._nativescriptIbeacon = new NativescriptIbeacon(this.beaconCallback(), options);

        if (!this._nativescriptIbeacon.isAuthorised()) {
            console.log("NOT Authorised");
            this._nativescriptIbeacon.requestAuthorization()
                .then(() => {
                    console.log("Authorised by the user");
                    this._nativescriptIbeacon.bind();

                }, (e) => {
                    console.log("Authorisation denied by the user");
                })
        } else {
            console.log("Already authorised");
            this._nativescriptIbeacon.bind();
        }
    }


    ngOnDestroy(): void {
        if (this._nativescriptIbeacon) {
            this._nativescriptIbeacon.unbind();
        }
    }

    beaconCallback() {
        var self = this;
        return {
            onBeaconManagerReady(): void {
                // start ranging and/or monitoring only when the beacon manager is ready

                self._nativescriptIbeacon.startRanging(self._region);
                self._nativescriptIbeacon.startMonitoring(self._region);
            },
            didRangeBeaconsInRegion: function(region: BeaconRegion, beacons: Beacon[]) {
                console.log(JSON.stringify(beacons));
            },
            didFailRangingBeaconsInRegion: function(region: BeaconRegion, errorCode: number, errorDescription: string) {
                console.error(`Failed to find beacons with errorCode: ${errorCode} and description:
                ${errorDescription}`);
            },
            didEnterRegion: function(region: BeaconRegion) {
                console.log("Did enter region called");
            },
            didExitRegion: function(region: BeaconRegion) {
                console.log("Did exit region called.");
            }
        }
    }

    ngOnInit(): void {

    }
}

 

For the most part, the codes are straightforward and based on the plugin’s documentation. However, a few things you may want to pay attention:

  • BeaconRegion encapsulates metadata you define for scanning beacons. You can scan for all the beacons having a same uuid. You can also narrow the scan to a specific group by supplying the major id, and further to a specific beacon by supplying the minor id.
  • On the android device, be sure to gain your apps access to Location. You can do so by going to Settings -> Apps -> {your app} -> Permissions and enable Location.
  • In beaconCallback() method, I use closure to capture the reference to my app component. That is because the method is a callback, which means the object which invokes it at a later time is not my app component, but rather some objects in the plugin. Therefore, had I use this keyword to access the objects defined in my app component, I would get errors because of accessing properties on an undefined object. This is just JavaScript.

This is what I get in the console, which let me know things work when I run the app on my android device:

onBeaconServiceConnect
JS: startRanging
JS: startRangingBeaconsInRegion
JS: startMonitoring
JS: didDetermineStateForRegion
JS: 1
JS: id1: b9407f30-f5f8-466e-aff9-25556b57fe6d id2: 17744 id3: 28116
JS: [{"proximityUUID":"b9407f30-f5f8-466e-aff9-25556b57fe6d","major":17744,"minor":28116,"distance_proximity":0.13055123127828835,"rssi":-60,"txPower_accuracy":-76}]

 

That’s it. Thanks for reading and happy coding.

References

Bluetooth low energy beacon

Determining the proximity to an ibeacon device

nativescript-ibeacon plugin

Related Posts
No related posts for this content

1 comment