Important: This guide describes the “monolithic” Estimote SDK, from  Estimote/iOS-SDK

The proximity detection features in that SDK are now obsoleted in favor of the new Estimote Proximity SDK, available at  Estimote/iOS-Proximity-SDK

To learn more about the new API, see the Add Proximity to iOS app guide instead.

Add beacon analytics to your app

This tutorial will guide you through the process of integrating your app with Estimote’s beacon analytics, enabling you to gather physical-world insight from your venues.

Estimote Cloud analytics dashboard

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 test the application.
  • 1 x Estimote Account (sign up here).
  • 1 or more Estimote Beacons.

We assume you already have an iOS app that you want to add beacon analytics to. If you don’t, and just want to try the analytics out, simply create an empty Xcode project and follow along.

Configure your beacons with unique UUID

All Estimote Beacons ship with their UUID set to a default value of B9407F30-F5F8-466E-AFF9-25556B57FE6D. To use your beacons for analytics, you need to generate yourself your own UUID, and configure your beacons to use it instead.

  1. Go to cloud.estimote.com.
  2. On the “Beacons” page, select all the beacons you want to use for analytics, using the checkboxes on the left. If you want to select all of your beacons, you can use the “master checkbox” to the left of the search box.
  3. Click the “Edit” button.
  4. Click the “Proximity UUID” dropdown, and then the “Generate New UUID” option. Naturally, you can type in your own UUID if you have a specific one in mind.
  5. Save the changes.

This will queue up the changes to the configuration of your beacons in Estimote Cloud. Now, use the Estimote iOS app to physically apply the new configuration to your beacons:

  1. On your iOS device, download and open the “Estimote” iOS app (available on the App Store) and go to the “Devices” section.
  2. Log in with your Estimote Account credentials using the “Log in” button in the top-right corner.
  3. Once logged in, go to the List view using the tab bar at the bottom. Beacons with pending configuration changes will show up with a cloud icon over them. The app will automatically start applying these changes to all the beacons in range, one by one.

Add geolocation to your beacons

One more step to get your beacons ready for analytics: in order to break the analytics data down to a venue level, we need you to tag your beacons with their geolocation.

  1. Go to cloud.estimote.com.
  2. On the “Beacons” page, select all the beacons deployed in a single venue, using the checkboxes on the left.
  3. Click the “Edit” button.
  4. Click the “Geo Location” dropdown, and then the “Create New Location” option.
  5. Enter the venue’s address: street, zip code, city, country. You can use the same phrase that takes you to your venue when typed into the Google Maps search.
  6. Save changes.

Repeat this for all your other venues.

The geolocation of your beacons is stored entirely in Estimote Cloud, so there’s no need to use the Estimote app to apply the changes, like we did in the previous section.

Add Estimote SDK to your app

Download 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.

Naturally, if your app uses a mix of Swift and Objective-C code, you likely already have a bridging header—in which case, you only need to add #import <EstimoteSDK/EstimoteSDK.h> to it.

Enable beacon analytics

Enabling beacon analytics is as simple as equipping your app with Estimote Cloud authorization credentials (so that we can upload analytics data to your account), having a beacon manager scanning for your beacons, and flipping on a switch to enable sending scan data to Estimote Cloud.

The best place to do all of that? Your AppDelegate and its didFinishLaunching method, as this will ensure beacon analytics are running as soon you start the app, and continue running at all times while the app is active.

class AppDelegate: UIResponder, UIApplicationDelegate  {

    var window: UIWindow?

    // 1. Add a property to hold the beacon manager and instantiate it
    let beaconManager = ESTBeaconManager()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // 2. Set up your Estimote Cloud credentials
        ESTConfig.setupAppID("<App ID>", andAppToken: "<App Token>")

        // 3. Enable analytics
        ESTConfig.enableRangingAnalytics(true)
        ESTConfig.enableMonitoringAnalytics(true)

        // 4. Start scanning for beacons
        self.beaconManager.startRangingBeacons(in: CLBeaconRegion(
            proximityUUID: UUID(uuidString: "<Your UUID>")!,
            identifier: "my beacons"))

        // ...
#import "AppDelegate.h"

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

@interface AppDelegate ()
// 2. Add a property to hold the beacon manager
@property (nonatomic) ESTBeaconManager *beaconManager;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 3. Set up your Estimote Cloud credentials
    [ESTConfig setupAppID:@"<App ID>" andAppToken:@"<App Token>"];

    // 4. Enable analytics
    [ESTConfig enableRangingAnalytics:YES];
    [ESTConfig enableMonitoringAnalytics:YES];

    // 5. Instantiate the beacon manager
    self.beaconManager = [ESTBeaconManager new];

    // 6. Start scanning for beacons
    [self.beaconManager startRangingBeaconsInRegion:
     [[CLBeaconRegion alloc] initWithProximityUUID:@"<Your UUID>"
                                        identifier:@"my beacons"]];

    // ...

If you don’t yet have an App ID and App Token for your app, you can generate one in Estimote Cloud: https://cloud.estimote.com/#/apps/add/your-own-app

Also, don’t forget to replace <Your UUID> with the actual UUID you’ve set for your beacons earlier in this guide.

Authorization to use location data

One more thing before we’re done: since being able to detect beacons means your app essentially gain access to user’s location inside a venue, iOS requires of you to ask the user for permission to access their location data. Without the appropriate permission, your app won’t be able to scan for beacons.

Info: If your app already uses Location Services, you must’ve already implemented the authorization request. If so, you can safely skip to the next section.

The request authorization dialog includes some space to explain to the user why your app wants to access their location, and what’s in it for them. This is your time few lines of text to shine, and convince them to hit that “allow” button!

Here’s how to set up the message:

  1. Go to the “Info.plist” file.
  2. Add a new row: the key should be NSLocationWhenInUseUsageDescription, and the type should be String.
  3. Now for the hardest part, the message itself. If you’re really out of ideas, maybe something along the lines of: “We use Bluetooth beacons to provide better in-app experience based on your location inside the venue.”

With the message defined, let’s request the access for our beacon manager. Going back to the didFinishLaunching method:

// add this line:
self.beaconManager.requestWhenInUseAuthorization()
// ... above this:
self.beaconManager.startRangingBeacons(in: CLBeaconRegion(
    proximityUUID: NSUUID(UUIDString: "<Your UUID>")!,
    identifier: "my beacons"))
// add this line:
[self.beaconManager requestWhenInUseAuthorization];
// ... above this:
[self.beaconManager startRangingBeaconsInRegion:
 [[CLBeaconRegion alloc] initWithProximityUUID:@"<Your UUID>"
                                    identifier:@"region"]];

Tip: Placing the requestWhenInUseAuthorization call in didFinishLaunching means that the authorization dialog will pop up immediately after starting the app for the first time. That’s because we wanted to keep things simple in this guide. For better user experience, you might want to incorporate the authorization dialog into your app’s onboarding process instead. It’s as simple as moving the method call. And by the way, you can call it on any ESTBeaconManager or CLLocationManager object in your app, as the authorization level is shared between all the beacon and location managers in the app.

Gathering analytics data in the background

With all of the above done, your app will now be gathering beacon analytics data whenever it’s active. What does “active” mean? Most commonly, it’s simply when the app is in the foreground, shown on screen. As soon as the user locks the phone, presses the home button, or navigates to another app, iOS will put your app into a suspended state after a few seconds. With the app suspended, scanning for beacons stops until the app comes into the foreground again.

Info: There’s actually a subtle difference between “active” and “in the foreground,” and under special circumstances it’s possible for an app to be active in the background. These are if your app:

  • uses background app refresh,
  • makes use of the background execution tasks,
  • implements any background modes that keep it active in the background (e.g., music playback).

That’s more of an interesting tidbit though, rather than something you can rely on to use analytics in the background. Background app refresh is controlled entirely by iOS and only wakes your app in the background for a short period of time. Background execution tasks are limited to a few minutes. Background modes are only reserved for certain use cases (music, navigation, VoIP apps, etc.)

Fortunately, if you want to use analytics in the background, there is a way!

iOS gives apps an option to subscribe to geofences, and will wake them up in the background whenever the device enters or exits a predefined geofence. Best part? Beacons can constitute geofences too, i.e., your app can be woken up every time you enter and exit range of a predefined beacon.

There’s a few catches though:

  • This requires the “always” authorization to access Location Services (instead of the “when in use” authorization we used above), and you can expect that the users of your app will be less likely to allow it to access their location at all times.
  • If the user agrees, iOS will still periodically remind them that your app is continuing to access their location even when not running—the user can simply acknowledge this message, or revoke the permission.
  • There’s a limit of 20 geofences per app, which means that ordinarily, you can only gather analytics in the background for up to 20 beacons.

On the upside:

  • This does not require the use of any background modes, background app refresh, or background execution tasks—the “always” authorization is enough.
  • Geofence monitoring is extremely energy efficient, and will not impact the battery usage of your app in any significant way.

Summing up, gathering beacon analytics in the background is perfectly doable, as long as you can:

  • Convince the user to allow your app to access their location data even when the app is not running. Best way to do that? Provide some actual functionality related to geofences, that the user will find valuable and useful!
  • Work around the 20-beacon limit. You can, e.g., only monitor for beacons closest to the user. Or, use Secure UUID feature of Estimote Beacons, which periodically rotates their UUID and thus, apart from securing your beacon network, has the side effect of being able to monitor for more than 20 beacons—using just the 20 geofences granted your app by iOS.

All of this requires a bit advanced setup than the one we’ve outlined in this article—but worry not, we’ll be happy to help you get it up and running! Drop us a message, and we’ll collectively figure out how to go about it.