Add Nearables to your app

In this guide, we’ll learn how to use the ESTTriggerManager to build a simple app interacting with nearables.

Info: While this tutorial covers building an iOS app, Estimote Android SDK also supports Nearables. Check out the Nearable Scanning on our Android SDK GitHub page to get started.

What’s ahead (aka Table of Contents)

Prerequisites

  • 1 x Mac computer with Xcode.
  • 1 x iPhone (4S or newer) or iPad (3rd gen or newer) to run the application.
  • 1 or more Estimote Stickers.

Create a stickers project

Start by creating a new, regular Xcode project using the “Single View Application” template. You can pick Swift or Objective-C, Estimote SDK works perfectly fine with both. Name it however you want; “Stickers” might be a good one.

Add Estimote SDK

Download the current version of the Estimote iOS SDK from GitHub:

https://github.com/Estimote/iOS-SDK/archive/master.zip

Unpack the archive, and drag-n-drop the EstimoteSDK.framework file (it’s in the EstimoteSDK sub-directory) to the Xcode project. Make sure to check the ‘Copy items if needed’ checkbox.

Tip: Estimote iOS SDK is also available from CocoaPods, just add pod 'EstimoteSDK' to your Podfile. CocoaPods is a simple way to add external libraries (like Estimote SDK) to your code, and keep them up-to-date easily. If don’t know it yet, we recommend giving it a try.

Swift users: add an Objective-C bridging header

Estimote SDK is written in Objective-C. It still works perfectly fine with Swift projects, but you need to take the additional step of adding a bridging header:

  1. Right-click on the project’s group in the project navigator, and choose “New File…”
  2. Pick a “Header File” from the “iOS - Source” section, and save it as ObjCBridge.h.
  3. Add #import <EstimoteSDK/EstimoteSDK.h> to the newly created file.
  4. Select your project in the navigator and go to “Build Settings.”
  5. Find the “Objective-C Bridging Header” setting and set it to ${PROJECT_NAME}/ObjCBridge.h.

Set up Location Services

The Nearable API uses a combination of the Nearable and the iBeacon packets broadcast by the stickers, and to be able to use the iBeacon one it requires access to Location Services. There’s no need to manually invoke the requestAlwaysAuthorization—the SDK will do it for you. You still need to come up with a message to be shown to the user when iOS prompts them to grant the app access to location data.

To do that, find the “Info.plist” file in the “Supporting Files” group in the project navigator, and add a new row in there. The key should be NSLocationAlwaysUsageDescription and the type should be String. Now for the hardest part: the message itself. We suggest something along the lines of:

We use Location Services to detect when you’re close to your nearables.

You might also consider throwing in a value-proposition in there, i.e., explain what cool features the user will be missing out on if they decline access. (e.g., We use location services to detect when you’re close to your nearables and remind you if you forget any of them when leaving.)

Enable Bluetooth LE background mode

To allow your app to detect Nearable packets in the background, we need to enable the “Uses Bluetooth LE accessories” Background Mode. Click on the root item (the one with the blue-print icon) in the project navigator on the left, then go to the “Capabilites” tab. Expand the “Background Modes” section, switch it on, and select the checkbox next to “Uses Bluetooth LE accessories”.

Info: Apple is very protective about the use of Background Modes in the App Store. If you’re submitting a Nearable app for review, make sure to mention it uses the Bluetooth LE background mode to detect nearables, and explain the value this background detection provides to the end-user of your app.

Add a trigger manager

Next up, let’s add a trigger manager to our view controller:

import UIKit

// 1. Add the ESTTriggerManagerDelegate protocol
class ViewController: UIViewController, ESTTriggerManagerDelegate  {

    // 2. Add the trigger manager
    let triggerManager = ESTTriggerManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        // 3. Set the trigger manager's delegate
        self.triggerManager.delegate = self
    }

// ...
#import "ViewController.h"

// 1. Add an import
#import <EstimoteSDK/EstimoteSDK.h>

// 2. Add the ESTTriggerManagerDelegate protocol
@interface ViewController () <ESTTriggerManagerDelegate>
// 3. Add a property to hold the trigger manager
@property (nonatomic) ESTTriggerManager *triggerManager;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 4. Instantiate the trigger manager & set its delegate
    self.triggerManager = [ESTTriggerManager new];
    self.triggerManager.delegate = self;
}

// ...

Set up rules and triggers

You can think of a trigger as an “if” statement, and of rules as the conditions: e.g., “if (in range of a ‘bike’ type sticker) and (sticker with identifier ‘XYZ’ is moving) then … else …”

Let’s compose a simple trigger, and pass it to the trigger manager to start monitoring for the trigger-defined events:

// this is where we left off:
self.triggerManager.delegate = self
// add this below:
let rule1 = ESTOrientationRule.orientationEquals(
                .HorizontalUpsideDown, forNearableType: .Bag)
let rule2 = ESTMotionRule.motionStateEquals(
                true, forNearableIdentifier: "54b128ebbc420d35")
let trigger = ESTTrigger(rules: [rule1, rule2], identifier: "tom the trigger")

self.triggerManager.startMonitoringForTrigger(trigger)
// this is where we left off:
self.triggerManager.delegate = self;
// add this below:
ESTRule *rule1 = [ESTOrientationRule orientationEquals:ESTNearableOrientationHorizontalUpsideDown
                                       forNearableType:ESTNearableTypeBag];
ESTRule *rule2 = [ESTMotionRule motionStateEquals:YES
                            forNearableIdentifier:@"54b128ebbc420d35"];
ESTTrigger *trigger = [[ESTTrigger alloc] initWithRules:@[rule1, rule2]
                                             identifier:@"tom the trigger"];

[self.triggerManager startMonitoringForTrigger:trigger];

Remember to replace the identifier in rule2 with that of your own sticker. You can discover the identifiers of your stickers on cloud.estimote.com, in the “Nearables” section, or by using the Estimote app.

Respond to trigger events

When all of the dreams rules a trigger is composed of come true, the trigger manager will call its delegate, notifying it about the change in the state of the trigger. Think about it as the “then” clause of the “if” statement analogy mentioned above. Similarly, once the condition is not true anymore (i.e., at least one of the rules is no longer satisfied), the delegate will be called again—this time, it’ll be like the “else” clause.

It’s probably best explained with the code, so let’s implement the delegate:

func triggerManager(manager: ESTTriggerManager,
                    triggerChangedState trigger: ESTTrigger) {
    if (trigger.identifier == "tom the trigger" && trigger.state == true) {
        print("Hello, digital world! The physical world has spoken.")
    } else {
        print("Goodnight. <spoken in the voice of a turret from Portal>")
    }
}
-(void)triggerManager:(ESTTriggerManager *)manager
  triggerChangedState:(ESTTrigger *)trigger {
    if ([trigger.identifier isEqualToString:@"tom the trigger"]
            && trigger.state == YES) {
        NSLog(@"Hello, digital world! The physical world has spoken.");
    } else {
        NSLog(@"Goodnight. <spoken in the voice of a turret from Portal>");
    }
}

Now, we’re ready to test it: run the app on your device, then turn your “bag” sticker upside-down and start waving the sticker the identifier of which you’ve put in the code. Shortly, you should see the “Hello” message in Xcode’s console. Now stop waving. “Goodnight.”

(And speaking of turrets from Portal, this will ruin your hopefully-productive-so-far day, we promise. Don’t click it. Okay, at least don’t say we didn’t warn you.)

Make it work in the background

Making your app detect stickers even when it’s not running requires the “Uses Bluetooth LE accessories” background mode. You can enable it by going to your project’s settings, on the “Capabilities” tab.

That’s … really it! Run the app on your device again, and once it starts, turn the screen off. Repeat the testing scenario. Note that iOS slows down the rate with which it scans for Bluetooth devices in the background, so it might take a bit longer for the trigger to kick in and greet the digital world on behalf of the physical one.

What’s next?

That’s pretty much all you need to know to get hacking on apps for nearables! You’ll find a comprehensive list of rules bundled with the Estimote SDK in the iOS SDK reference. (Hint: look for the classes with “rule” in name (-:)