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.
Part 1: Setting up
In this tutorial, we’ll take you through the process of building a simple iOS app with Estimote SDK and iBeacon. We’ll also explain the fundamental concepts, possibilities and limitations of the iBeacon technology as we go.
The main theme is that of an airport app.
What’s ahead (aka Table of Contents)
- Prerequisites
- Create a beacon project
- Add Estimote SDK
- Add a beacon manager
- Authorization to use Location Services
- Key takeaways
Prerequisites
- 1 x Mac computer with Xcode.
- 1 x iPhone (4S or newer) or iPad (3rd gen or newer) to run the application.
- 1 x Estimote Account (sign up here).
- 1 or more Estimote Beacons with iBeacon broadcasting enabled.
Create a beacon 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; “Airport” might be a good one.
Add Estimote SDK
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:
- Right-click on the yellow folder with your app’s name in the project navigator, and choose “New File…”
- Pick a “Header File” from the “iOS - Source” section, and save it as
ObjCBridge.h
(don’t change the automatically-suggested folder). - Add
#import <EstimoteSDK/EstimoteSDK.h>
to the newly created file, and save the file. - Select your project in the navigator and go to “Build Settings.”
- Find the “Objective-C Bridging Header” setting and set it to
${TARGET_NAME}/ObjCBridge.h
.
Add a beacon manager
Now that our project is all hooked up with the Estimote SDK, let’s create ourselves an instance of an ESTBeaconManager
—the gateway to (almost all) interactions with Estimote Beacons.
The great thing about beacon-enabled apps is, they can be launched into the background by iOS when the user enters range of a beacon—even if the phone is in the user’s pocket, the screen’s locked, and the app was terminated earlier (e.g. to free up memory for other apps). This means we need to be careful about where to place the beacon manager—View Controllers for example won’t be created if the app is launched straight into the background.
Fortunately, AppDelegate’s didFinishLaunching
makes for a perfect spot, since it’ll be called regardless of whether the app is launching into the foreground or background. So let’s go ahead and set up the beacon manager in there.
import UIKit
// 1. Add the ESTBeaconManagerDelegate protocol
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, ESTBeaconManagerDelegate {
var window: UIWindow?
// 2. Add a property to hold the beacon manager and instantiate it
let beaconManager = ESTBeaconManager()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
// 3. Set the beacon manager's delegate
self.beaconManager.delegate = self
return true
}
// ...
#import "AppDelegate.h"
// 1. Add an import
#import <EstimoteSDK/EstimoteSDK.h>
// 2. Add the ESTBeaconManagerDelegate protocol
@interface AppDelegate () <ESTBeaconManagerDelegate>
// 3. Add a property to hold the beacon manager
@property (nonatomic) ESTBeaconManager *beaconManager;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 4. Instantiate the beacon manager & set its delegate
self.beaconManager = [ESTBeaconManager new];
self.beaconManager.delegate = self;
return YES;
}
// ...
Authorization to use Location Services
One more thing before we can proceed: since iBeacon is part of iOS’s Location Services stack (the same one which apps can use to obtain latitude & longitude position of the user via GPS, WiFi and cellular towers), it’s necessary to ask the user of your app for permission to access their location data.
First, we need to define the message that’ll be shown to the user when iOS asks them to grant the app access to Location Services. Better be convincing—or else, no beacons for you!
-
Go to the “Info.plist” file.
-
Add a new row: the key should be
NSLocationAlwaysUsageDescription
and the type should beString
. -
Now for the hardest part, the message itself. How about:
“We use low-energy Bluetooth and iBeacon devices installed at the airport to find you inside the hall, and provide relevant information. You don’t need to know security wait times when you’re already at the gate, do you?”
Tip: We think there are two key features every good “usage description” message should sport.
First and foremost, the value proposition. Make sure the user understands the benefits of trading their highly-valued location data with your app.
Second, we believe it’s a good idea to mention that it’s all Bluetooth based. Most people will assume that Location Services are about GPS, and might be concerned with the battery drain. Addressing that should give you bonus points!
Second, let’s request the authorization. When this code executes for the first time, it’ll show a popup with the message we’ve just defined.
// this is where we left off:
self.beaconManager.delegate = self
// add this below:
self.beaconManager.requestAlwaysAuthorization()
// this is where we left off:
self.beaconManager.delegate = self;
// add this below:
[self.beaconManager requestAlwaysAuthorization];
Info: There are two levels of authorization to access location data in iOS: “always” (which we’re using above) and “when in use.” The former allows access even if the app is not running, and latter allows access only when the app is shown on the screen. To fully benefit from iBeacon’s background capabilities, we need the “always” authorization.
Important: You do not need any Background Modes enabled for iBeacon to work in the background! This a very common misconception circulating the Internet, but it can get your app rejected by Apple during the app review process. For iBeacon, the “always” authorization is all that is needed.
Key takeaways
-
To add Estimote SDK to your project, drag-n-drop the framework file into it and use the
#import <EstimoteSDK/EstimoteSDK.h>
as your import. In Swift, you also need to add an Obj-C bridging header. -
ESTBeaconManager
is the central piece to all interactions with beacons. Beacon events are delivered to its delegate, which should conform to theESTBeaconManagerDelegate
protocol. -
The beacon manager can sometimes execute code even if the app is not visible on screen or even running. In such cases, it’s imperative to instantiate the manager as part of the AppDelegate’s
applicaton:didFinishLaunching
method. -
iBeacon requires permission to access Location Services. Use the
requestAlwaysAuthorization
method of the beacon manager to request it. Put the explanation that’ll be shown to the user in the Info.plist file, under theNSLocationAlwaysUsageDescription
.