{"id":1554,"date":"2015-06-07T10:37:01","date_gmt":"2015-06-07T16:37:01","guid":{"rendered":"http:\/\/dev.iachieved.it\/iachievedit\/?p=1554"},"modified":"2015-06-07T10:37:01","modified_gmt":"2015-06-07T16:37:01","slug":"writing-an-ibeacon-app-in-swift","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/writing-an-ibeacon-app-in-swift\/","title":{"rendered":"Writing an iBeacon App in Swift"},"content":{"rendered":"<p><b>Editor&#8217;s Note:<\/b>  This is Part Two of our series of articles on creating a Swift <a href=\"http:\/\/en.wikipedia.org\/wiki\/IBeacon\">iBeacon<\/a> application.  By the end of the <i>series<\/i> you will have written a &#8220;game&#8221; in Swift called <i>You&#8217;re Getting Warmer!<\/i> which allows you to track down and find a beacon.  <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/getting-started-with-ibeacon\/\">Part One<\/a> gets you up and running iBeacon with a Gimbal Proximity Beacon Series 10.<\/p>\n<p>Before getting started with Part Two, you should have an operating iBeacon and know its UUID.  If you don&#8217;t have an iBeacon start with <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/getting-started-with-ibeacon\/\">Part One<\/a> of this series!<\/p>\n<p>If you&#8217;re working with iBeacon we&#8217;re just going to assume you known how to create a new <b>Single View Application<\/b> Swift project with Xcode.  Go ahead and do that now.  We named our project <code>gettingwarmer<\/code>.<\/p>\n<p><center><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2015\/06\/gettingwarmer_xcodeproj.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2015\/06\/gettingwarmer_xcodeproj.png\" alt=\"gettingwarmer_xcodeproj\" width=\"257\" height=\"264\" class=\"aligncenter size-full wp-image-1571\" \/><\/a><\/center><\/p>\n<h3>Beacon Ranging<\/h3>\n<p>There are two methods of listening for iBeacons in iOS:  <i>monitoring<\/i> and <i>ranging<\/i>.  The difference between the two is that <i>monitoring<\/i> is an activity that can continue running in the background, while <i>ranging<\/i> is a foreground activity.  Radius Networks wrote up a <a href=\"http:\/\/developer.radiusnetworks.com\/2013\/11\/13\/ibeacon-monitoring-in-the-background-and-foreground.html\">nice explanation<\/a> describing the differences in detail.  Apple&#8217;s <a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/UserExperience\/Conceptual\/LocationAwarenessPG\/RegionMonitoring\/RegionMonitoring.html\">iBeacon documentation<\/a> uses the term <i>ranging<\/i> to describe the activity of determining the proximity of a given iBeacon.   Our first application will make use of ranging as opposed to monitoring.<\/p>\n<h3>BeaconManager<\/h3>\n<p>I have always preferred to use the singleton &#8220;manager&#8221; pattern for working with CoreLocation in iOS.  We&#8217;ll create a class called <code>BeaconManager<\/code> which will be responsible for an instance of <code>CLLocationManager<\/code> as well as serving as our <code>CLLocationManager<\/code> delegate.  To get started create a new file <code>BeaconManager.swift<\/code> in your <code>gettingwarmer<\/code> Xcode project and add the following implementation:<\/p>\n<pre>\r\nimport Foundation\r\nimport CoreLocation\r\n\r\nclass BeaconManager : NSObject, CLLocationManagerDelegate {\r\n  \r\n  static let sharedInstance = BeaconManager()\r\n  \r\n  var locationManager:CLLocationManager\r\n  \r\n  override init() {\r\n    self.locationManager = CLLocationManager()\r\n    \r\n    super.init()\r\n    \r\n    self.locationManager.delegate = self\r\n    self.locationManager.requestWhenInUseAuthorization()\r\n    \r\n  }\r\n  \r\n  func startRanging() {\r\n  }\r\n  \r\n  \/\/ MARK:  CLLocationManagerDelegate methods\r\n  func locationManager(manager: CLLocationManager!,\r\n                       didChangeAuthorizationStatus status: CLAuthorizationStatus) {\r\n  }\r\n  \r\n  func locationManager(manager: CLLocationManager!,\r\n                       didRangeBeacons beacons: [AnyObject]!,\r\n                       inRegion region: CLBeaconRegion!) {\r\n\r\n  }\r\n  \r\n  \r\n}\r\n<\/pre>\n<p>The class declaration and <code>init<\/code> routine should be self-explanatory.  If you haven&#8217;t been working with Swift 1.2 you may have missed the introduction of the <code>static<\/code> keyword which allows for a quick implementation of the singleton pattern.<\/p>\n<p>Let&#8217;s first implement the <code>didChangeAuthorizationStatus<\/code> method, because once we are authorized we want to start ranging.<\/p>\n<p>Here&#8217;s our implementation:<\/p>\n<pre>\r\n  \/\/ MARK:  CLLocationManagerDelegate methods\r\n  func locationManager(manager: CLLocationManager!,\r\n    didChangeAuthorizationStatus status: CLAuthorizationStatus) {\r\n      switch status {\r\n      case .NotDetermined:\r\n        self.locationManager.requestWhenInUseAuthorization()\r\n      case .AuthorizedWhenInUse, .AuthorizedAlways:\r\n        self.startRanging()\r\n      case .Denied, .Restricted:\r\n        NSNotificationCenter.defaultCenter().postNotificationName(\"LOCATION_DENIED\", object: nil)\r\n      default:\r\n        break\r\n      }\r\n  }\r\n<\/pre>\n<p>If the OS can&#8217;t determine the authorization status (<code>.NotDetermined<\/code>), we&#8217;ll simply ask for it again (why not).<\/p>\n<p>If we receive a callback that our status is <code>.AuthorizedWhenInUse<\/code> (what we requested) or <code>.AuthorizedAlways<\/code> (which will never be the case), we&#8217;ll call our <code>startRanging<\/code> method.<\/p>\n<p>If on the other hand we receive <code>.Denied<\/code> or <code>.Restricted<\/code>, we&#8217;ll broadcast a notification with <code>NSNotificationCenter<\/code> that will be heard by our <code>ViewController<\/code>.  The <code>ViewController<\/code> will then be responsible for raising a dialog indicating that location services are required for the app to operate properly.<\/p>\n<p>Now, let&#8217;s take a look at our <code>startRanging<\/code> method.<\/p>\n<pre>\r\n  func startRanging() {\r\n    \r\n    let uuid   = NSUUID(UUIDString:\"788FA98B-871C-4C71-9944-88ADEC84A8DA\")\r\n    let region = CLBeaconRegion(proximityUUID: uuid, identifier: \"\")\r\n    self.locationManager.startRangingBeaconsInRegion(region)\r\n    \r\n  }\r\n<\/pre>\n<p>Ranging begins with the <code>startRangingBeaconsInRegion<\/code> method, and in our case a <i>region<\/i> is identified as &#8220;being in the proximity of a beacon broadcasting a UUID of 788FA98B-871C-4C71-9944-88ADEC84A8DA&#8221;.  It&#8217;s that simple.  If iOS hears a beacon with this UUID, it is &#8220;in&#8221; that region.<\/p>\n<p>It may be confusing at first that a &#8220;region&#8221; in this context is not geographical.  Apple&#8217;s QuickHelp documentation explains it this way:  &#8220;<i>A CLBeaconRegion object defines a type of region that is based on the device\u2019s proximity to a Bluetooth beacon, as opposed to a geographic location.<\/i>&#8221;<\/p>\n<p>Once ranging starts we have to be prepared to receive <code>didRangeBeacons<\/code> calls on our <code>CLLocationManager<\/code> delegate.  For now, we&#8217;ll add this implementation:<\/p>\n<pre>\r\n  func locationManager(manager: CLLocationManager!,\r\n    didRangeBeacons beacons: [AnyObject]!,\r\n    inRegion region: CLBeaconRegion!) {\r\n      \r\n      let beaconsRanged = beacons as! [CLBeacon]!\r\n      \r\n      if let beacon = beaconsRanged.last {\r\n        println(\"Beacon ranged:  \\(beacon)\")\r\n      }\r\n  }\r\n<\/pre>\n<p>Before leaving ranging, it is important to draw the distinction between <i>monitoring<\/i> for regions and <i>ranging<\/i> beacons.  Monitoring can run in the background with notifications sent to your app when the registered <code>CLBeaconRegion<\/code> is &#8220;entered&#8221; (that is, the beacon was heard).  Ranging is for finer proximity detection and can only be used while the application is in the foreground.  Again, reading the Radius Networks <a href=\"http:\/\/developer.radiusnetworks.com\/2013\/11\/13\/ibeacon-monitoring-in-the-background-and-foreground.html\">article<\/a> is useful.<\/p>\n<h3>Rounding Out<\/h3>\n<p>Thus far we&#8217;ve implemented:<\/p>\n<ul>\n<li>a <code>BeaconManager<\/code> class capable of requesting location services authorization\n<li>the <code>didChangeAuthorizationStatus<\/code> method to handle changes in location services authorization from the user\n<li>a <code>startRanging<\/code> method which will start listening for our iBeacon\n<li>the <code>didRangeBeacons<\/code> method which will be called when iOS hears our iBeacon\n<\/ul>\n<p>We have a few more things to do before running the application:<\/p>\n<ul>\n<li>setting NSLocationWhenInUseUsageDescription in our <code>Info.plist<\/code>\n<li>creating an instance of the <code>BeaconManager<\/code> when our <code>ViewController<\/code> appears\n<li>intercepting <code>LOCATION_DENIED<\/code> notifications in the event the user declines location services authorization\n<\/ul>\n<p>In your <code>Info.plist<\/code>, create a new key called <code>NSLocationWhenInUseUsageDescription<\/code> like so:<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2015\/06\/infoplist.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2015\/06\/infoplist.png\" alt=\"infoplist\" width=\"893\" height=\"205\" class=\"aligncenter size-full wp-image-1569\" \/><\/a><\/p>\n<p>Next, round out the <code>ViewController<\/code> code by adding the following:<\/p>\n<pre>\r\n  override func viewDidAppear(animated: Bool) {\r\n    super.viewDidAppear(animated)\r\n    \r\n    NSNotificationCenter.defaultCenter().addObserver(self, selector: \"locationDenied\", name: \"LOCATION_DENIED\", object: nil)\r\n    let beaconManager = BeaconManager.sharedInstance\r\n  }\r\n\r\n  func locationDenied() {\r\n    let alert = UIAlertController(title:\"Permission Required\", message:\"Location services permission is required.\", preferredStyle:.Alert)\r\n  \r\n    let ok = UIAlertAction(title: \"OK\", style: .Default) { (action) -> Void in\r\n    }\r\n  \r\n    alert.addAction(ok)\r\n    self.presentViewController(alert, animated:true){}\r\n  }\r\n<\/pre>\n<p>When our view appears we want to create an instance of the <code>BeaconManager<\/code> which in turn will request authorization.  Therefore we add our <code>ViewController<\/code> as an <code>NSNotification<\/code> observer for the <code>LOCATION_DENIED<\/code> notification.  If this notification is received we pop up an alert dialog (<code>UIAlertController<\/code>) indicating that location services permission is required.  <\/p>\n<h3>Run It!<\/h3>\n<p>If you&#8217;ve implemented everything you should now be able to run the application on your iOS device (note:  this will not work in a simulator).  After granting location services authorization and bringing out our iBeacon we see in the console:<\/p>\n<p>[objc]<br \/>\nBeacon ranged:  CLBeacon (uuid:&lt;__NSConcreteUUID 0x1702224e0&gt; 788FA98B-871C-4C71-9944-88ADEC84A8DA, major:1, minor:0, proximity:2 +\/- 0.68m, rssi:-59)<br \/>\n[\/objc]<\/p>\n<h3>What Could Possibly Go Wrong?<\/h3>\n<p>Software development can be rewarding and a lot of fun, but it can also drive you crazy when things don&#8217;t work right.  In this series there are a lot of things that could go wrong that would prevent iOS from recognizing your beacon.  If you&#8217;re having trouble, consider:<\/p>\n<ul>\n<li>is your iBeacon programmed with the same UUID as your <code>CLBeaconRegion<\/code>?\n<li>is your iBeacon powered?\n<li>was the app granted location services permission?\n<li>is the iBeacon in range?\n<li>is Bluetooth enabled on your iOS device?\n<\/ul>\n<h3>Getting the Code<\/h3>\n<p>The complete source code for this tutorial is available on <a href=\"https:\/\/bitbucket.org\/joeiachievedit\/gettingwarmer\">BitBucket<\/a>.  The implementation for this article is available on the <code>partTwo<\/code> branch.<\/p>\n<h3>Next Up<\/h3>\n<p>We can now receive iBeacon messages in our application, but we aren&#8217;t doing anything with the information.  In Part 3 of this series we&#8217;ll go through the various properties of the <code><a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/CoreLocation\/Reference\/CLBeacon_class\/\">CLBeacon<\/a><\/code> class, namely:<\/p>\n<ul>\n<li>proximity\n<li>accuracy\n<li>rssi\n<\/ul>\n<p>We&#8217;ll then begin adding a user interface to our view controller for a nice game of <i>You&#8217;re Getting Warmer!<\/i>.  Stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Editor&#8217;s Note: This is Part Two of our series of articles on creating a Swift iBeacon application. By the end of the series you will have written a &#8220;game&#8221; in Swift called You&#8217;re Getting Warmer! which allows you to track down and find a beacon. Part One gets you up and running iBeacon with a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,18,5],"tags":[],"class_list":["post-1554","post","type-post","status-publish","format-standard","hentry","category-apple","category-ibeacon","category-swift"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/1554"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=1554"}],"version-history":[{"count":22,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/1554\/revisions"}],"predecessor-version":[{"id":1578,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/1554\/revisions\/1578"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=1554"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=1554"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=1554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}