Written by Brightec Team
Mar 30, 2016

Turning an iPhone into an iBeacon

Want to experiment with iBeacons but can’t afford the technology? Perhaps an iPhone is the answer instead.

iBeacons are...

iBeacons are basically simple devices that your iOS device can detect within a short range. The iBeacon allows the user to start interacting with it when in its proximity. 

In this tutorial, we’ll help you setup your project to work with iBeacons. 

However, you might not want to invest in an iBeacon straightaway. Particularly if you’re only in the development stages of a project, or if you’re just doing some research and development.

An easy solution is to turn your iPhone into an iBeacon, and it’s easy than you think.

First things first - make sure you have Bluetooth enabled on your device.

Setting up the emitter

// Needed module for iBeacons
@import CoreLocation;
@import CoreBluetooth;

The above module is necessary in order to get all the BLE magic working. Here are the properties you will need to get the phone transmitting like an iBeacon:

@interface EmitterViewController () 


// The region defined by our beacon, with all the information representing it
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
// The option we will use to set up the phone as a peripheral
@property (strong, nonatomic) NSDictionary *peripheralData;
// Object responsible of transforming your phone into a transmitter, with all the method that goes with it 
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;


@end

Those properties can either be in your .m or .h file (it has no importance for this tutorial).

iBeacon properties

An iBeacon is defined by three distinct properties : 

  • A UUID
  • A ‘major’ value
  • A ‘minor’ value 

The UUID is there to make sure your beacons are linked to your application, and it ensures other beacons won’t interfere with the experience you put in place for the user.

In order to create a UUID simply:

  • Open terminal
  • Type uuidgen
  • Copy the result

The major and minor are there to differentiate the beacons within your own app. Usually, the major will be used to represent a room and the minor will be a beacon within that room. 

Ready to broadcast

Time to set up the beacon and start broadcasting:

- (void)prepareBeacon
{
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"8532DD11-5F36-4120-ADF2-C32A14145D06"];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                                major:1
                                                                minor:1
                                                           identifier:@"com.Brightec.iBeacon"];
}

- (void)startBeacon
{
    self.peripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:nil];
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
                                                                     queue:nil];
}

In startBeacon, you’ll keep a strong copy of the peripheralData and peripheralManager to ensure they won’t be cleaned in the memory by accident.

The delegate method

Calling the startBeacon method doesn’t necessarily tell you if the device successfully started broadcasting as a beacon or not. This is why we set our class as a cbperipheralmanagerdelegate in the interface. This way we have the following delegate method: 



- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        // Update your UI to indicate the beacon is now on
        [self.labelStatus setText:@"Beacon currently broadcasting"];
        [self.peripheralManager startAdvertising:self.peripheralData];
    }
    else if (peripheral.state == CBPeripheralManagerStatePoweredOff) {
        // Update your UI to indicate the beacon is now off
        [self.labelStatus setText:@"Beacon currently not broadcasting"];
        [self.peripheralManager stopAdvertising];
    }
    else {
        // Update your UI to indicate there was something wrong
        NSLog(@"Something went wrong, current status : %ld", (long)peripheral.state);
        [self.peripheralManager stopAdvertising];
    }
}

In the delegate method, you can update your UI to communicate to the user the current status of the beacon.

Setting up the receiver

// Needed module to listen for iBeacons
@import CoreLocation;

Unlike before, you just need CoreLocation to listen and discover iBeacons :

@interface ReceiverViewController ()  

// The kind of region we will be listening for
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
// Use location services to find beacons
@property (strong, nonatomic) CLLocationManager *beaconLocaliser;

@end

The class is a CLLocationManagerDelegate because we will want to use the class delegate for each occurrence of entry into the influence zone of an iBeacon.

Setting up the iBeacon

First in your viewDidLoad you want to set up the location manager and prepare it to listen for the iBeacons, the code here is very similar as if you were doing geo-fencing.

- (void)viewDidLoad
{
    self.beaconLocaliser = [[CLLocationManager alloc] init];
    [self.beaconLocaliser setDelegate:self];
}

In order to prepare your beacon to listen, you will have to listen to the UUID of your beacons (as we created it earlier). If we were using actual iBeacon devices, you would have to set them up properly beforehand. 

 



- (void)initBeaconLocaliser
{
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"8532DD11-5F36-4120-ADF2-C32A14145D06"];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                           identifier:@"com.Brightec.iBeacon"];
    [self.beaconLocaliser startMonitoringForRegion:self.beaconRegion];
}

So we are re-using the same UUID and bundle identifier as before ensuring our phone will be picked up by our beacon listener. Once again we keep a strong reference in the code to make sure nothing will be accidentally cleaned by ARC.

The delegates

The delegates here will fire when entering and leaving the zone of influence of an iBeacon. When detecting the signal of a beacon you will want to start ranging the beacon in order to get more information.



// when picking up the signal of an iBeacon
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    [self.beaconLocaliser startRangingBeaconsInRegion:self.beaconRegion];
}

// When leaving the signal of an iBeacon
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(nonnull CLRegion *)region
{
    [self.beaconLocaliser stopMonitoringForRegion:self.beaconRegion];
}

When you start monitoring the beacons in range, the following delegate method will be called. This will take place every time a piece of information changes (regarding at least one of the beacons in range). 



// More information for the beacons in Range
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
    CLBeacon *beacon = [[CLBeacon alloc] init];
    beacon = [beacons lastObject];

    NSLog(@"Beacon Major : %@", beacon.major.description);
    NSLog(@"Beacon Minor : %@", beacon.minor.description);

    NSLog(@"Beacon Accuracy : %f", beacon.accuracy);

    if (beacon.proximity == CLProximityUnknown) {
        NSLog(@"Proximity : Unknown Proximity");
    }
    else if (beacon.proximity == CLProximityImmediate) {
        NSLog(@"Proximity : Immediate");
    }
    else if (beacon.proximity == CLProximityNear) {
        NSLog(@"Proximity : Near");
    }
    else if (beacon.proximity == CLProximityFar) {
        NSLog(@"Proximity : Far");
    }
}

A quick note regarding the beacon.proximity, it greatly varies depending on the signal you are receiving. It can be affected by more parameters than just distance (for example a wall, a crowd standing around, etc). You'll have to take that into account. In order to do so you can look at the beacon.rssi that will give you the beacon signal strength in decibels. Now you are ready to detect your own beacon and create your own experience for your users.

In conclusion

Playing around with iBeacons is a lot of fun, we've even managed to make one out of a raspberry pie (don't ask).

One great idea we had was to install them in museums. Imagine having an iBeacon under every piece of art. They could be used to enhance the experience of visually impaired people or to describe the history surrounding the exhibit.  Even to add some gamification for children.

iBeacons have a lot of potential, get experimenting! 

This article was originally written for Brightec by Lionel Mille

Top