iBeacons are small Bluetooth Low Energy (LE) devices that use proximity sensing to transmit a universally unique identifier (UUID). For example, it can allow retailers to know where users are around their store and push targeted information to customer’s mobile devices. In business terms, retailers can immediately send customers anything from discounts and coupons to new product information and availability based on their location in-store.

The technology behind these devices relies on broadcasting a small packet of information that includes at least three values:

  • proximityUUID: “Universally Unique Identifier” shared among related beacons
  • Major number: 16-bit integer value
  • Minor number: 16-bit integer value

An example of iBeacons in action:

Let’s say a large grocery store chain wanted to engage customers with iBeacons. The store would first set up several beacons with the same proximityUUID, enabling mobile apps to recognize that the customer is in one of the grocery’s stores. The company would then set a different Major number for each individual store and finally, set a Minor number to certain aisles within the store.

Now when a customer enters the grocery store with the proper application, the store’s iBeacons can trigger useful in-app information based on what aisle or department the customer is browsing. With the development and release of Apple’s new programming language, Swift, there will be an easier alternative for writing and implementing iBeacon apps.

Creating an iBeacon app using Swift requires 3 main steps to prepare for app creation:

  • First, Developers must add the Core Location Framework, which uses a mobile device’s hardware to determine a user’s position. The Framework also allows the hardware to monitor when a user crosses the boundaries of a region with a Bluetooth device.
  • The next step is setting up Background Modes to use Location Updates and Bluetooth LE accessories. This allows the app to keep monitoring and receiving notifications while in the device’s background.
  • Last, set the Text Shown when asking special permission for always-on location monitoring. This is a new requirement with iOS 8. It is necessary to go into Info.plist and add a Row with a key of NSLocationAlwaysUsageDescription, Type set to String, then set the Value to a custom string.

Now that the foundation is complete, the iBeacon app is ready for creation. The first step? Set up a Region for monitoring. This happens by creating a CLBeaconRegion, which looks for iBeacons with the UUID defined in the code snippet below. To create a Region, add the following code to didFinishLaunchingWithOptions:

1
2
3
4
5
6
7
8
9
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    ...
    func application(application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            let uuidString = "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6"
            let beaconIdentifier = "com.makeandbuild"
            let beaconUUID:NSUUID = NSUUID(UUIDString: uuidString)
            let beaconRegion:CLBeaconRegion = CLBeaconRegion(proximityUUID: beaconUUID,
                identifier: beaconIdentifier)

When a device’s Region comes in range of an iBeacon it triggers a notification. There are two ways of receiving notifications: First, receiving information when the device enters or exits the range of a beacon (it is best to use startMonitoringForRegion to create this function). And, when an iBeacon is in range, it can return the relative distance of the device to the iBeacon using startRangingBeaconsinRegion.

After defining a region it is necessary to tell the device to monitor its location. This means creating an instance of CLLocationManager along with defining a Delegate to be notified when the Location Manager returns a notification. Once created, the app will need to tell the Location Monitor to start monitoring, begin ranging for beacons within the Region, and start updating the location. All three of these must be included to receive range information when the app is in the background.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    var locationManager: CLLocationManager?
    func application(application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            ...
            locationManager = CLLocationManager()
 
            if(locationManager!.respondsToSelector("requestAlwaysAuthorization")) {
                locationManager!.requestAlwaysAuthorization()
            }
 
            locationManager!.delegate = self
            locationManager!.pausesLocationUpdatesAutomatically = false
 
            locationManager!.startMonitoringForRegion(beaconRegion)
            locationManager!.startRangingBeaconsInRegion(beaconRegion)
            locationManager!.startUpdatingLocation()

Swift Note: Declaring the locationManager with a question mark is necessary because it is empty when the AppDelegate object is created. This means making it optional. It is created in the didFinishLaunchingWithOptions method. Because it is optional, it is important to use an exclamation mark after its name in following instances, as shown in the code above.

To accomplish these functions in iOS 8, it is necessary for the app to request permission to send notifications. The following code needs to be added to the bottom of the didFinishLaunchingWithOptions method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    func application(application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            ...
            if(application.respondsToSelector("registerUserNotificationSettings:")) {
                application.registerUserNotificationSettings(
                    UIUserNotificationSettings(
                        forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound,
                        categories: nil
                    )
                )
            }
            return true
    }
    ...

This code allows the app to function normally on iOS 7 but will request user permission to send notifications on iOS 8. With everything set up, the next step is creating an extension to send a push notification showing the proximity of the nearest iBeacon. The following code must to be added at the very bottom of AppDelegate.swift, outside the existing class declaration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
extension AppDelegate: CLLocationManagerDelegate {
 func beaconNotificationMessage(message: String!) {
        let notification:UILocalNotification = UILocalNotification()
        notification.alertBody = message
        UIApplication.sharedApplication().scheduleLocalNotification(notification)
    }
     
    func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: AnyObject[]!,
        inRegion region: CLBeaconRegion!) {
            let viewController:ViewController = window!.rootViewController as ViewController
            viewController.beacons = beacons as CLBeacon[]?
            viewController.tableView.reloadData()
             
            NSLog("didRangeBeacons");
            var message:String = ""
             
            if(beacons.count > 0) {
                let nearestBeacon:CLBeacon = beacons[0] as CLBeacon
                 
                if(nearestBeacon.proximity == lastProximity ||
                    nearestBeacon.proximity == CLProximity.Unknown) {
                        return;
                }
                lastProximity = nearestBeacon.proximity;
                 
                switch nearestBeacon.proximity {
                case CLProximity.Far:
                    message = "Proximity: Far"
                case CLProximity.Near:
                    message = "Proximity: Near"
                case CLProximity.Immediate:
                    message = "Proximity: Immediate"
                case CLProximity.Unknown:
                    return
                }
            } else {
                message = "No beacons"
            }
             
            NSLog("%@", message)
            beaconNotificationMessage(message)
 
    }

As illustrated above, the didRangeBeacons event has an ordered Array of CLBeacon’s, for which each can have one of the following proximity values:

  • CLProximityUnknown
  • CLProximityImmediate
  • CLProximityNear
  • CLProximityFar

The Received signal strength indication (RSSI) denotes the CLBeacon’s signal strength measured in decibals. In addition the accuracy is provided as a numerical value measured in meters. The combination of these values gives business owners better control of their targeted messages. This is particularly handy when using multiple iBeacons in a store. Using the grocery store example, combining the values above can determine customer specific information, like what side of the aisle a customer is browsing, and when the customer is approaching new items in the store.

Exploring new ways to apply iBeacons will drive further innovation of their capabilities. For now, these basic foundations for building iBeacon apps with Swift open up a world of opportunities including and beyond retail marketing.

Relevant Links

Github – https://github.com/makeandbuild/ibeaconSearch
The Swift Programming Language iBook – iBook link