You can put any bytes into an iBeacon advertisement that you wish, but iOS severely limits which of these bytes you can read. If you need to use iOS to read these data, you only have four bytes of bluetooth advdata you can change that will be readable by iOS. If you only care about reading the bytes with other operating systems (OSX Mavericks, Android, Linux) then this is not a problem.
To explain the limits of iOS, it helps to take a look at the advdata of a typical iBeacon advertisement, which looks like this:
4C 00 # Company identifier code (0x004C == Apple)
02 15 # iBeacon advertisement indicator
e2 c5 6d b5 df fb 48 d2 b0 60 d0 f5 a7 10 96 e0 # ProximityUUID
00 00 # Major
00 00 # Minor
c5 # The 2's complement of the MeasuredPower
iOS does not allow you to access the raw bytes of the advdata shown above using its CoreBluetooth
APIs. (See here for more details.) If you use the iBeacon ranging functions of CoreLocation
, you can read the ProximityUUID
(16 bytes), Major
(2 bytes) and Minor
(2 bytes) out of the advdata. The MeasuredPower
that is set in the code example you mentioned is NOT directly readable in iOS. It simply is used as an input to the algorithm used to estimate distance from the RSSI. (See here for details.) Changing the MeasuredPower
in the advertisement will affect this distance estimate, but you can not reliably determine the actual MeasuredPower
value. So you cannot use it as a custom variable.
As described above, an iBeacon advertisement also includes a 16-byte ProximityUUID
. But the iOS CoreLocation
APIs don't let you see any iBeacon advertisements unless you specify the matching ProximityUUID
up front. So it really isn't any use as a custom variable.
What can you use as a custom variable? The two values you can use for custom variables are the Major
field and the Minor
fields. Each of these is two bytes and if you tell iOS CoreLocation
to range all iBeacons that have a given ProximityUUID
, you will get ranging updates telling you the Major
and Minor
values for each, and you can encode any data in these fields you want. To access these, use simply read the values like this:
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
for (CLBeacon *iBeacon in iBeacons) {
// write code here to do something with iBeacon.major and iBeacon.minor
// which each will have values from 0-65535
}
}
All of the above is an iOS-only restriction. Other platforms let you see the full bytes of the advdata, so you can use any of the bytes you want as custom variables. If you still want them to be recognized as iBeacons, however, you should leave the second two bytes (the iBeacon advertisement indicator) alone.
For custom variables, the best practice is to use lookup table to tie the standard iBeacon identifiers (ProximityUUID
, Major
, Minor
) to data fields. This lookup table can be embedded in your app, or it can use a web service like Radius Networks' ProximityKit to do do this automatically.
Full disclosure: I am Chief Engineer for Radius Networks.