TUTORIAL: Developing iOS Applications with iBeacons in Objective-C and Swift

estimote1_4

Development Kit from Estimote

Since Apple introduced iBeacons in iOS 7, those small cute devices have slowly, but confidently conquered museums, exhibitions, retail stores and universities. Apple uses iBeacons in their retail stores and the technology will definitely be getting even more attention in the future. In this tutorial, we’ll experiment with a developer kit from Estimote to create a location aware app using Estimote SDK.  The developer kit contains three iBeacons that are more than enough to get started with iBeacons.

Estimote SDK is a small wrapper around Apple’s CoreLocation framework. Therefore, it’s easy to get started with Estimote SDK after exploring CoreLocation documentation.  Estimote SDK is available here: https://github.com/Estimote/iOS-SDK

Complete code

You can find the complete code here (tested with Xcode 6 beta 6):

The demo: simple app with iBeacons

The application, which was created for this tutorial, is very simple and depicts a simple plan of an office or a shop. Let’s say that colorful boxes are rooms in the office. For each room we have a beacon installed.

screenshot1

 

Whenever we are close enough to the beacon (in this example less than 7 meters), its area is highlighted and when we are even closer to the beacon (e.g less than 3 meters), a modal view is shown with additional information (picture or URL).

Screenshot 2014.08.20 19.29.53

Screenshot 2014.08.22 21.23.39

Getting started

Open Xcode and Create a new project by choosing the Single View Application template. If you’re using XCode 6, choose whether Swift or Objective-C on the screen. This tutorial covers both Swift and Objective-C.

Screen Shot 2014-08-20 at 19.52.42

 

Add following frameworks to the project:

  • CoreLocation.framework
  • CoreBluetooth.framework
  • SystemConfiguration.framework

Also, you need to add Estimote SDK. You can use CocoaPods or copy the downloaded directory manually to the project. You can download Estimote SDK here: https://github.com/Estimote/iOS-SDK

The next step is to create a local file called beacons.json. It will contain all information about our beacons and actions that are associated with them.

Each beacon is identifiable by 3 components: UUID, major and minor. It is sometimes reasonable to have only one UUID for all your beacons and differentiate beacons using only majors-minors. However, the latest Estimote hardware version requires UUIDs to be different for every beacon, so different UUIDs will be used in this tutorial.

In addition to identifiers, different actions are associated with each beacon. Each action represents a distance range from the beacon and says what to do when a person has entered or exited the defined range.

User interface

The main user interface is extremely simple and contains of a background image with our “rooms”, a label for debug information and semitransparent overlay views for each room. Each such overlay view should have its tag set to the major number of the corresponding beacon. It will be afterwards easier to whether show or hide overlays by using those tags. All overlay views are hidden by default (set alpha to 0).

Screen Shot 2014-08-20 at 20.35.26

Screen Shot 2014-08-21 at 11.05.06

Bridging header for Swift

If you’re writing in Swift, the bridging header should be added, containing following declarations:

Checking device capabilities

In order to start using iBeacons in the app, several settings should be turned on. It is a good idea to notify user, if there is something wrong with his device settings. This check is performed whenever the app starts or becomes active.

Objective-C:

Swift:

Parsing the JSON file 

In order to conveniently manage all our beacons, the beacons.json file will be mapped to the data structure containing MMBeacon object to represent a beacon, MMBeaconAction object for an action and MMBeaconsArray for wrapping beacons collection and providing convenient sorting and accessory methods.

An important note is that MMBeacon doesn’t use plain distance to the beacon, instead it calculates an average distance based on last three distances reported by the SDK. It also doesn’t save the change, if it wasn’t significant. That’s because distances information coming from beacons is very unstable and can fluctuate much. Using an average distance is an attempt to make things more stable.

The method to calculate an average distance looks as following:

Objective-C:

Swift:

MMBeacon should also have a method for getting its currently active actions.

Objective-C:

Swift:

The action is considered active, if the average distance to its beacon is within the declared action’s range. However, there is a difference, for action’s entry and exit. Action is entered, when the distance to its beacon is smaller than the action’s activation distance in meters. Action is exited, when the distance to its beacon is bigger than activation distance + 1 meter. Therefore, to exit the the action, you need to move further away. It is done because of unstable distances.

Objective-C:

Swift:

Managing beacons

Our demo app will range beacons only when it’s active, because it only shows overlays and highlights areas nearby the beacon.

In iOS 8 a special authorization request is needed to start getting location updates. Location updates are needed only when the app is active, therefore method requestWhenInUseAuthorization should be used. Estimote SDK hasn’t yet been updated to support this method, therefore as a temporary workaround, the CLLocationManager instance is declared in the delegate.

Objective-C:

Swift:

Location manager is authorized during the application’s launch:

Objective-C:

Swift:

There should also be a key NSLocationWhenInUseUsageDescription  set in the application’s info.plist file with a description, why your app needs location updates.

Info.plist:

In order to see the beacons, they should be monitored by the app. It’s the first required step to detect the beacons.

Objective-C:

Swift:

To maximize beacons responsiveness and avoid latency, the ranging is started right away after monitoring has started. Otherwise there would be latency.

Objective-C:

Swift:

When app goes to the background, the ranging is stopped:

Objective-C:

Swift:

Start ranging again once the app is active:

Objective-C:

Swift:

To manage callbacks, the ESTBeaconManagerDelegate protocol is implemented.

In case of an error, an alert with the error message is shown:

Objective-C:

Swift:

When a region is exited, its ranging is finished. When it’s entered again, the ranging is started:

Objective-C:

Swift:

The most important callback for this demo app is “didRangeBeacons”, as it provides distance info updates that are used by the app.

Objective-C:

Swift:

This method is called once per advertising interval for every region. The beacon’s advertising interval can be changed, but the smaller it is, the shorter will be beacon’s battery life.

What is done in this method?

1. Estimote beacon is mapped to our datasource. An average distance of our beacon is updated.

Objective-C:

Swift:

2. All ranged beacons are sorted by their distance.

Objective-C:

Swift:

3. The delegate is notified about active beacons change. The debug info label is updated.

Objective-C:

Swift:

4. Entered and exited actions are found by comparing currently active actions with actions that were active during the last callback.

Objective-C:

Swift:

5. The delegate is notified about entered and exited actions change.

Objective-C:

Swift:

Beacon Manager Delegate methods implementation

The main viewcontroller should implement beacon manager’s delegate methods in order to respond to location updates with UI updates.

The simplest part is changing the debug info label’s text:

Objective-C:

Swift:

The action’s entry and exit are similar, besides using different action’s identifier: “entryAction” or “exitAction”

Objective-C:

Swift:

The remaining part is to perform some action based on its identifier using the action’s object if it’s needed.

Objective-C:

Swift:

Actions themselves are straightforward:

1. Activate area

Objective-C:

Swift:

2. Deactivate area

Objective-C:

Swift:

3. Show picture

Objective-C:

Swift:

4. Hide picture or URL

Objective-C:

Swift:

5. Show URL in WebView

Objective-C:

Swift:

Complete code

You can find the complete code for iBeacons here (tested with Xcode 6 beta 6):

2 Comments
  1. Victor Castano
  2. Luciano

Leave a Reply

Your email address will not be published. Required fields are marked *

*