September 25, 2013

Play ‘Find The Monkey’ with iOS 7 iBeacons

By

We’re going to make a fun little monkey finder app here using iBeacons. iBeacons are an exciting new technology available in iOS 7 that allows iOS devices to locate each other when nearby. The API for detecting an iBeacon is part of the Core Location framework, and should feel similar to the APIs used for geographic region monitoring that have existed for some time. However, what distinguishes iBeacons from the traditional region monitoring API of Core Location, is that iBeacons use Bluetooth Low Energy. This makes scenarios such as indoor region monitoring possible on iOS.

Additionally, the Bluetooth Low Energy APIs available in the Core Bluetooth framework make it easy for an iOS device to become an iBeacon.

Let’s look at an example to illustrate this.

The application we’ll create here is called FindTheMonkey. A user will walk around with an iPhone looking for a monkey in an iPad. As the device gets closer to the monkey, the user will be told if he or she is getting warmer, culminating in the joy of finding the monkey.

The following screenshots show the application as the user moves around with the iPhone looking for the monkey.

The iPad side contains the iBeacon itself, with a user interface showing the monkey:

In this scenario, we’ll create a universal application where the iPad version is the iBeacon, while the iPhone version uses the region monitoring API to “find” the iBeacon.

The code for creating the iBeacon is simple. Just create a CLBeaconRegion with an NSUuid to identify the beacon, and pass the CLBeaconRegion to a CBPeripheralManager instance from the Core Bluetooth framework. Then, simply call StartAdvertising on the peripheral manager, as shown below:

    var monkeyUUID = new NSUuid (uuid);
    var beaconRegion = new CLBeaconRegion (monkeyUUID, monkeyId);
    //power - the received signal strength indicator (RSSI) value (measured in decibels) of the beacon from one meter away
    var power = new NSNumber (-59);
    NSMutableDictionary peripheralData = beaconRegion.GetPeripheralData (power);
    peripheralDelegate = new BTPeripheralDelegate ();
    peripheralMgr = new CBPeripheralManager (peripheralDelegate, DispatchQueue.DefaultGlobalQueue);
    peripheralMgr.StartAdvertising (peripheralData);

The power indicates the signal strength in decibels one meter from the beacon, which is used to control how far the proximity regions are from the device. We’ll use this to change the status from “cold” to “warm” as the iPhone gets closer to the beacon.

To monitor the beacon from the iPhone, use the Core Location framework. As with geographic region monitoring, the CLLocationManager will report any region changes to the application. For example, the RegionEntered event, which exposes the callback from the CLLocationManager in an easy to use C# event, allows us to display a notification when the user enters the beacon region:

    locationMgr = new CLLocationManager ();
    locationMgr.RegionEntered += (object sender, CLRegionEventArgs e) => {
        if (e.Region.Identifier == monkeyId) {
            var notification = new UILocalNotification () { AlertBody = "There's a monkey hiding nearby!" };
            UIApplication.SharedApplication.PresentLocationNotificationNow (notification);
        }
    };

Here we also check that region entered is the one we’re interested in, namely the monkey beacon’s region, by checking the Identifier property. Then we create a local notification to tell the user that we entered beacon’s region, which in our scenario informs the user that a monkey is nearby. This way if the user had opened the app and was greeted with a message that “there aren’t any monkeys nearby” they could get an alert banner when entering the region sometime later after closing the app, as shown below:

Tapping the notification would take the user into the app where they could begin their quest for a monkey.

To kick off region monitoring, so that we can receive the above region entered callback, we simply call the location manager’s StartMonitoring method, passing it a CLBeaconRegion created with the same NSUuid and identifier that we used in the peripheral:

    locationMgr.StartMonitoring (beaconRegion);

This gets us region monitoring between the beacon running on the iPad and the Core Location code running on the iPhone. But how do we get the finer grained feedback telling us when the iPhone gets closer to the beacon after it has entered the region?

For this, another event, DidRangeBeacons, is used. In this event, we’ll get the beacons that are in range, of which there will be one in our case. If there are multiple beacons in range, the first beacon in the array will be the closest. The Proximity of the beacon will contain information as to which range the device is in with respect to the beacon. This is a CLProximity enum containing the four possible values for Proximity, which from closest to furthest are: Immediate, Near and Far, or Unknown if the proximity could not be determined.

We’ll can use this information to update the display with a new status message and change the color of the view:

    locationMgr.DidRangeBeacons += (object sender, CLRegionBeaconsRangedEventArgs e) => {
        if (e.Beacons.Length > 0) {
            CLBeacon beacon = e.Beacons [0];
            switch (beacon.Proximity) {
            case CLProximity.Immediate:
                monkeyStatusLabel.Text = "You found the monkey!";
                View.BackgroundColor = UIColor.Green;
                break;
            case CLProximity.Near:
                monkeyStatusLabel.Text = "You're getting warmer";
                View.BackgroundColor = UIColor.Yellow;
                break;
            case CLProximity.Far:
                monkeyStatusLabel.Text = "You're freezing cold";
                View.BackgroundColor = UIColor.Blue;
                break;
            case CLProximity.Unknown:
                monkeyStatusLabel.Text = "I'm not sure how close you are to the monkey";
                View.BackgroundColor = UIColor.Gray;
                break;
            }
        }
    };

As with region monitoring, the ranging process is kicked off from the location manager, only this time calling StartRangingBeacons:

    locationMgr.StartRangingBeacons (beaconRegion);

Run the app on the iPad and the iPhone and see how the status message and view color change as you move varying distances from the iPad where the beacon is advertising.

The sample project containing the code shown here is available at https://github.com/mikebluestein/FindTheMonkey.

Also, be sure to check out the C# port of Apple’s AirLocate sample, as well as Larry O’Brien’s blog post on iBeacons.

I hope you enjoyed this simple example using iBeacon. There are many use cases where this is a compelling technology, ranging from in store commerce, to manufacturing plant material tracking. I’m looking forward to seeing what people come up with.

TwitterFacebookGoogle+LinkedInEmail