I want to transmit iBluetooth over android with the BluetoothLeAdvertiser class from android.bluetooth.le. But it seems I can't set some of the Manufacturer spec data fields to match those of the iBeacon.
iBeacon structure:
This and this tell you what an iBeacon's Manufacturer spec data values need to contain. Basically:
Apple Company Identifier (Little Endian), 0x004c = 76
data type, 0x02 => iBeacon
data length, 0x15 = 21
uuid: 585CDE931B0142CC9A1325009BEDC65E
major: [0000]
minor: 0000
meaured power at 1 meter: 0xc5 = -59
I've been following this tutorial that has these steps:
Create the AdvertiseData object using AdvertiseData.Builder.addManufacturerData() (which I believe should be the Manufacturer spec data, see below for the issues with that)
protected void setAdvertiseData() { AdvertiseData.Builder mBuilder = new AdvertiseData.Builder(); ByteBuffer mManufacturerData = ByteBuffer.allocate(24); byte[] uuid = getIdAsByte(UUID.fromString("0CF052C2-97CA-407C-84F8-B62AAC4E9020")); mManufacturerData.put(0, (byte)0xBE); // Beacon Identifier mManufacturerData.put(1, (byte)0xAC); // Beacon Identifier for (int i=2; i<=17; i++) { mManufacturerData.put(i, uuid[i-2]); // adding the UUID } mManufacturerData.put(18, (byte)0x00); // first byte of Major mManufacturerData.put(19, (byte)0x09); // second byte of Major mManufacturerData.put(20, (byte)0x00); // first minor mManufacturerData.put(21, (byte)0x06); // second minor mManufacturerData.put(22, (byte)0xB5); // txPower mBuilder.addManufacturerData(224, mManufacturerData.array()); // using google's company ID mAdvertiseData = mBuilder.build(); }
Create AdvertiseSettings using the AdvertiseSettings.Builder
protected void setAdvertiseSettings() { AdvertiseSettings.Builder mBuilder = new AdvertiseSettings.Builder(); mBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER); mBuilder.setConnectable(false); mBuilder.setTimeout(0); mBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM); mAdvertiseSettings = mBuilder.build(); }
Broadcast the AdvertiseSettings and AdvertiseData using BluetoothLeAdvertiser. (This also takes a callBack that tells if Bluetooth transmission worked, no problems there)
mBluetoothLeAdvertiser.startAdvertising(mAdvertiseSettings, mAdvertiseData, mAdvertiseCallback);
The problem with these steps are:
It's not clear where AdvertiseData.Builder.addManufacturerData() is putting its second Byte[] manufacturerSpecificData parameter in terms of the Manufacturer spec data, especially because the first parameter of AdvertiseData.Builder.addManufacturerData() is also the Manufacturer Type field in the Manufacturer spec data
The following BluetoothLeAdvertiser constructor parameters seem to write bytes to the Manufacturer spec data, overwriting the Bytes added in addManufacturerData
- AdvertiseSettings.Builder.setTxPowerLevel and PeriodicAdvertisingParameters.Builder.setIncludeTxPower would overwrite the TX power (RSSI) set in AdvertiseData.Builder.addManufacturerData() and would overwrite each other when combined in some of the other BluetoothLeAdvertiser functions like BluetoothLeAdvertiser.startAdvertisingSet.
- Although it's not shown in the example I gave, AdvertiseData.Builder also has the function addServiceUuid which would overwrite the UUID added in AdvertiseData.Builder.addManufacturerData()
At first I was following this tutorial, and was transmitting an Alt-Beacon. Perhaps the BluetoothLeAdvertiser class is assuming I'm still transmitting Alt-Beacon which is differently structured than iBeacons.
Alt-Beacon structure:

other resources:
updated code
public AdvertiseData getiBeaconData() {
AdvertiseData.Builder mBuilder = new AdvertiseData.Builder();
ByteBuffer mManufacturerData = ByteBuffer.allocate(24);
byte[] uuid = getIdAsByte(UUID.fromString(thisCont.getString( R.string.ble_uuid )) );
ParcelUuid parced = new ParcelUuid(UUID.fromString(thisCont.getString( R.string.ble_uuid )) );
/*
R.string.ble_uuid == CDB7950D-73F1-4D4D-8E47-C090502DBD63 this is about the iBeacon structure http://smlie-blog.blogspot.com/2014/06/bluetooth-ibeacon-packet-format.html */
//mManufacturerData.put((byte)0x00); //Manufactor Id 1
//mManufacturerData.put((byte)0x4C); //Manufactor Id 2
// mManufacturerData.put((byte)0xBE); //ibeconid1
mManufacturerData.put((byte)0x02); //ibeconid2
mManufacturerData.put((byte)0x15); //Data length
for (byte i:uuid) {
mManufacturerData.put(i); // adding the UUID
}
mManufacturerData.put((byte)0x00); //major first
mManufacturerData.put((byte)0x00); //major second
mManufacturerData.put((byte)0x00); //minor first
mManufacturerData.put((byte)0x00); //minor second
//mManufacturerData.put((byte)0xC5); //TX power
/*
mManufacturerData.put((byte)0x1A); // Beacon Identifier was BE iBeacon = 00
mManufacturerData.put((byte)0xFF); // Beacon Identifier was AC iBeacon = 02
/* the above 2 lines are the ibeacon AD Indicator
for (byte i:uuid) {
mManufacturerData.put(i); // adding the UUID
}
mManufacturerData.put((byte)0x00); // first byte of Major
mManufacturerData.put((byte)0x00); // second byte of Major
mManufacturerData.put((byte)0x00); // first minor
mManufacturerData.put((byte)0x00); // second minor
mManufacturerData.put((byte)0xC5); // txPower (RSSI) (from tx)
mBuilder.addManufacturerData(16, mManufacturerData.array()); // using google's company ID
*/
mBuilder.addManufacturerData(76, mManufacturerData.array()); // using google's company ID
//mBuilder.addServiceUuid(parced);
return mBuilder.build();
}