Tutorial: Making a Smarter iBeacon Detector on iOS Using PubNub | Guest Post

Apple has been using BLE on its devices since the iPhone 4S. Because of that great head start, using your iPhone to detect beacons is much easier than on any other platform! In fact, Apple’s iBeacon protocol was the first to take advantage of the great qualities of BLE communication.

In our previous tutorials, we walked through an overview of beacon technology and how to build an iBeacon emitter.

In this tutorial, we will make a smarter iBeacon detector (ie. observer)!

Using PubNub and iBeacon, we can create two-way communication while still keeping the low energy asset of beacons! You’ll want to read a little bit on how we plan on doing this, this article will give you a high-level explanation on how our app is supposed to function. This weird, but simple setup increases the capabilities of iBeacons greatly!

We will first look into how to turn your iPhone into an iBeacon in Swift, and we will build the PubNub structure over it!

What are we waiting for? Let’s build amazing apps! This article is inspired by this example app so feel free to use some of its available source code.




Using your iPhone to detect iBeacons

In the scope of this tutorial, we will build a minimal app on which you can build upon and improve. As a result, we won’t really get into building the user interface. We want to keep it clean and simple.

Setting up your View Controller

First things first, let’s import our libraries.

import UIKit
import CoreLocation
import CoreBluetooth

That’s all we’ll need for this.

The variables you’ll need in your view controller are as follows. We’ll talk more about them later on.

var region = CLBeaconRegion()
var locationManager = CLLocationManager()
let uuid = NSUUID(UUIDString: “0CF052C2-97CA-407C-84F8-B62AAC4E9020″)

For the sake of simplicity, we will have most of our application in the viewDidLoad() method. It’s up to you to arrange it as you wish.

override func viewDidLoad() {
region = CLBeaconRegion(proximityUUID: uuid, identifier: "com.yourcampany.example")
self.locationManager.delegate = self

The first thing we need to do here is create a region element. The beacon region element defines how the proximity to a beacon or a set of beacon should or will look like. What this means in our example is that we are defining beacon regions that have our specified UUID. As a result, when we will detect beacons, we will only detect those with this particular UUID. We could have just as well initiated our region with a UUID, major and minor which would have limited our detection to beacons which satisfy all 3 conditions.

The next step is to create a location manager instance. The location manager is the element that will allow us to use the iPhone’s hardware to start detecting beacons. We will need to set a delegate which will call the location manager’s methods when certain events will be triggered. We set our view controller as the delegate. Don’t forget:

class YourViewController: UIViewController, CLLocationManagerDelegate {

For iOS 8 or more, it is necessary for the app to request the user’s authorization to use location tools. This line usually will not suffice. You have to manually add a couple lines in the info.plist file which is located in the “Supporting Files” directory. If you right click on it and open it as “Source Code”, you want to make sure you add these lines inside the “<dict>” markup.

<string>Location services required for iBeacon</string>
<string>Location services required for iBeacon</string>

When the user first starts the app, a pop up dialog box will ask the user to authorize location services along with the string we just defined.


We can finally start monitoring for our beacon region!

For now on, our view controller will be waiting for the following events:

  • didStartMonitoringForRegioin
  • monitoringDidFailForRegion
  • didEnterRegion
  • didExitRegion

We will only implement one of those methods:

func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
self.locationManager.starRangingBeaconsInRegion(region as CLBeaconRegion)

When we started monitoring for regions, we are only subscribing to entering and leaving a region events. In the scope of our app, we need more information. Remember, we want our iPhone to connect to PubNub when we get close enough to a beacon. To save some energy, we will start to range beacons only when we enter a region of interest.

This will trigger a didRangeBeacons:inRegion: method much more frequently than the didEnterRegion method. It will be called as soon as the distance to the beacon changes.

func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: NSArray!, inRegion region: CLBeaconRegion!) {
var beacon = beacons.lastObject as CLBeacon
switch beacon.proximity {
case CLProximity.Immediate:

Alright! I hope we cleared out the logic for using Apple’s tools to detect our iBeacons. The next step here is to make our iPhone compatible with our smarter emitting beacon. If we want to establish a two-way communication with the beacon, we want to subscribe to the same PubNub channel as soon as we get close enough (you can think that “Near” distance suffice, here we will require to get at “Immediate” distance to start the communication).

Making your iBeacon Smarter with PubNub

Getting Started

The first thing you will need is the pubnub library for iOS.

We are going to use cocoa pods. If you don’t use it yet, you’re missing out. Easy installation and starter’s guide here.

In your project’s root directory

$ pod init
$ {your favorite editor} Podfile

Your podfile should look like:

platform :ios, “8.0”
target “YourProject” do
pod ‘PubNub’, ‘3.7.2’
target “YourProjectTests” do

You can make sure you are using the latest version of pubnub here.

Now you just need to type

$ pod install

Close Xcode, and open the YourProject.xcworkspace .

That wasn’t too hard right? It’s not quite over though.

Use Objective-C libraries in Swift

The pubnub library is written in Objective-C, but we are coding in swift. All you need to do now is to build a bridging header. Create a new Objective-C header in your project called YourProject-Bridging-Header.h for good practice, and type:

#ifdef __OBJC__
#import &lt;UIKit/UIKit.h&gt;
#import &lt;Foundation/Foundation.h&gt;
#import "PNImports.h"

Now in your project’s configuration panel, go to build settings and scroll down to the “Swift Compiler – Code Generation” section. Set the “install Objective-C Bridging Header” to Yes and in “Objective-C Bridging Header” type the path from your project’s root directory to your bridging header. It’ll be something like “YourProject/YourProject-Bridging-Header.h”


All set? Let’s roll.

Initializing PubNub

For the sake of simplicity, we will code our PubNub behaviour on the same view controller.

We will need to add 3 variables to our class:

let config = PNConfiguration(forOrigin:"your.company.com", publishKey: "demo", subscribeKey: "demo", secretKey:nil)
var channel = PNChannel()
var isSubscribed = false

When a user connects to PubNub, he is identified with the content of this PNConfig object. For the scope of this tutorial, we will use demo keys. Get yours here!

In the viewDidLoad method, we will also start PubNub. Add these lines and don’t forget to set your class as a PNDelegate:


Awesome! We are connected to PubNub!

We want to use the data advertised by the beacon to subscribe to the beacon’s channel.

Subscribing to the PubNub channel

We need to add a couple line to our didRangeBeacons method in order to subscribe once we get at “Immediate” distance from the beacon:

func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: NSArray!, inRegion region: CLBeaconRegion!) {
var beacon = beacons.lastObject as CLBeacon
if (beacon.proximity == CLProximity.Immediate &amp;&amp; !isSubscribed) {
self.channel = PNChannel.channelWithName("YourCompany_\(beacon.minor)_\(beacon.major)", shouldObservePresence: false) as PNChannel

That’s it. We just need to make sure we did not already subscribe to the channel.

func pubnubClient(client: PubNub!, didSubscribeOnChannels channels:NSArray!) {
self.isSubscribed = true

On the beacon’s side, our subscription event should trigger the beacon to send a message on the channel. We need to implement the method which will be called whenever a message is sent on the channel.

func pubnubClient(client: PubNub!, didReceiveMessage message: PNMessage!) {

Alright! We just received the message! We are good to go. It’s up to you to figure out what you want to do with it.

Finally, when we exit a region, we will want to stop all of these processes:

func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
self.locationManager.stopRangingBeaconsInRegion(region as CLBeaconRegion!)

func pubnubClient(client: PubNub!, didUnsubscribeOnChannels channels: NSArray!) {
self.isSubscribed = false

With just a few lines of code, you just created a two-way communication with a beacon while still having a low energy consumption! How great is that? We hope you liked this article.

Next, we’ll build an iBeacon emitter.


Guest Authors 

Norvan Sahiner and Sunny Gleason wrote this tutorial series on behalf of PubNub, a platform that allows you to build and scale realtime apps for connected devices.

One Response to “Tutorial: Making a Smarter iBeacon Detector on iOS Using PubNub | Guest Post”

  1. Hello,
    we are developing, for some months now, a more generic cloud-based platform for doing a similar thing this post is trying to accomplish. With a few differences:
    – beacon-type agnostic – at least for Android, it can handle ANY type of beacon, not just iBeacons
    – data-centric – the real-time connection (pub/sub based) will actually carry payloads of data for the beacons around, back to the app that will handle that data.

    We have just released the public SDK for Android that enables this, if you are interested or have any feedback you can visit our (not yet polished) website overhere: http://onebeacon.io



Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>