📜 ⬆️ ⬇️

An example of working with iBeacon technology using Swift

Considering the growing interest in using Bluetooth beacons in various areas ranging from animal chipping, navigation in the museum exposition and ending with the most popular function of stock notifications in stores, we at Techmas prepared an introduction for their implementation. Perhaps someone from the developers who are only planning to create their own applications and still do not know where to start, the instruction below will help to understand the basic concepts and capabilities of the technology. Despite the fact that there is already a set of SDKs for working with beacons, we only use Swift and CoreLocation and CoreBluetooth libraries.




')

Let's start with the theory of the technology itself. At the end of 2014, Bluetooth Special Interest Group (SIG) released the Bluetooth v4.2 specification (Bluetooth Low Energy, BLE).

Following the description, we have a signal of 31 bytes in size in the form of a Scan Response Data packet. This packet is divided into so-called AD structures, which are sequences of bytes of various predefined sizes. Taking into account that 16 bytes from this packet should go to a 128-bit device UUID, a large amount of data from one beacon cannot be obtained.

The iBeacon standard was introduced by Apple in 2013. In it, the BLE signal contains a MAC address and two AD structures. While the first AD structure contains general information, the second is directly related to iBeacon. Consider it in more detail.

The first byte contains information about the length of the structure of 26 bytes (0x1A), followed by one byte per type, which indicates that it belongs to the manufacturer. Next comes the Apple ID (0xFF). The next two bytes to the beacon indicators, which are always 0x02 and 0x15 (one byte for each). As we wrote above, the device UUID takes 16 bytes. Total for the Major and Minor fields is only 2 bytes. The last field TX Power can be used to calibrate the beacon (1 byte).

General package layout:



Having studied the basic concepts, let's return to the Apple SDK for working with beacons and write a simple application for displaying information about the nearest beacon.

We used beacons purchased here . They are a small box size 46mm * 36mm * 18mm:


Sample code can be taken in Github .

Let's start with connecting the necessary libraries:

import UIKit import CoreLocation import CoreBluetooth 


Next, we define the variables, the purpose of which will be discussed in more detail later.
 var locationManager = CLLocationManager() var region = CLBeaconRegion() 


For simplicity, we will mainly use the viewDidLoad () method. In it we define:
 override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self } 


The region object defines the search area for beacons and allows it to be limited by the parameters of beacons: uuid , the value of the major and minor fields.

 let region = CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"), identifier: "ru.techmas.techbeacon") 


Next, we have a locationManager object, which accesses the device itself to search for beacons and tracks the events of their detection. To do this, you need to assign our controller as the locationManager delegate:

 class ViewController: UIViewController, CLLocationManagerDelegate { 


In addition, starting with iOS 8, the application must request authorization to use geolocation functions. We can use the methods locationManager.requestWhenInUseAuthorization () and locationManager.requestAlwaysAuthorization () . They differ in that the first allows the use of geolocation only with the active application window, while the second provides access at any time.

Using the constructor, add the line to the info.plist, which is contained in the Supporting Files directory:



To prevent the warning from occurring every time, use the authorizationStatus () method of the CLLocationManager class:

 if (CLLocationManager.authorizationStatus() != CLAuthorizationStatus.AuthorizedWhenInUse) { locationManager.requestWhenInUseAuthorization() } 


Now we are ready to search for beacons!

Add a call to the search method:
 locationManager.startRangingBeaconsInRegion(region) 


To display information about the detected beacons, we define a new method:
 func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) { } 


Inside the delegate method, we have access to the beacons that our locationManager found. To display information about them, just add the line to the console:
 println(beacons) 


Let's try to display information about the nearest beacon on the screen.

Determine the nearest beacon:
 let knownBeacons = beacons.filter{ $0.proximity != CLProximity.Unknown } if (knownBeacons.count > 0) { let closestBeacon = knownBeacons[0] as! CLBeacon } 


The closestBeacon object has the fields we mentioned above:


Let us dwell on the proximity field, which is of the enum type. To get information in the form of a string, we need:
 var proximityString = String() switch proximity { case .Near: proximityString = "" case .Immediate: proximityString = "" case .Far: proximityString = "" case .Unknown: proximityString = "Unknown" } 


The resulting data will display. The code will look like this:
 func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) { println(beacons) let knownBeacons = beacons.filter{ $0.proximity != CLProximity.Unknown } if (knownBeacons.count > 0) { let closestBeacon = knownBeacons[0] as! CLBeacon major_label.text = String(stringInterpolationSegment: closestBeacon.major) minor_label.text = String(stringInterpolationSegment: closestBeacon.minor) let proximity = closestBeacon.proximity var proximityString = String() switch proximity { case .Near: proximityString = "" case .Immediate: proximityString = "" case .Far: proximityString = "" case .Unknown: proximityString = "Unknown" } proximity_label.text = proximityString rssi_label.text = String(closestBeacon.rssi) accuracy_label.text = String(stringInterpolationSegment: closestBeacon.accuracy) } } 


Our application will be:


We hope that our description will help developers to quickly understand the technology of iBeacon and start creating new applications. In the following articles we will explain how to prepare the structure of indoor navigation using a set of beacons, use notifications when a signal enters the zone, and much more.

Source: https://habr.com/ru/post/264561/


All Articles