I currently have only one 5.0 phone to test this on (Moto E2 3G on 5.0 Lollipop), but I am not able to advertise Custom UUID's on Android 5.0. When I say a custom UUID I mean one that isn't predefined by the Bluetooth LE spec.
On my Nexus 6 Android 5.1, everything works fine.
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
// Advertising this spec assigned UUID works
//ParcelUuid temp = new ParcelUuid(UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"));
// Advertising this custom UUID doesn't work!!
ParcelUuid temp = new ParcelUuid(UUID.fromString("02FD04F4-CFFF-4573-B478-F7470A7CF2F2"));
dataBuilder.addServiceUuid(temp);
settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED); settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
settingsBuilder.setConnectable(true);
AdvertiseData ad = dataBuilder.build();
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), ad, null, advertiseCallback);
When viewing the Advertising packet of the Moto E2 with a custom UUID, here's what I can see - notice there is no information about the Service UUID:
If I advertise an assigned service UUID on the Moto E2 (0000180D-0000-1000-8000-00805f9b34fb
), I can see the 16-bit representation of the UUID is available:
If I advertise a custom UUID on the Nexus 6, I see the UUID data as expected:
Is anyone able to confirm this behaviour on another 5.0 device? Do I need to make the minimum supported version 5.1? The only other related reference I've been able to find on the internet about this, is this empty ticket on the Android bug tracker.
I can confirm that this is a bug on the Moto G 2014 running 5.0.2 (and possibly other devices and/or versions).
My workaround is to just insert your custom UUID into the manufacturer data instead of the service UUID field. This will only work if you have access to the central that is scanning for it and can explicitly check the manufacturer data to see if the UUID is present in making your decision to connect.
With my implementation I had control over what the central checks to decide whether to connect, so I just adopted this scheme for all Android devices that operate in the peripheral mode, instead of using the normal 'addServiceUuid" method. Tested on Galaxy S6 (5.0.2) and Nexus 5X (6.0) and it's working.
private AdvertiseData buildAdvertiseData()
{
int manufacturerID = 0x0001;
byte[] uuidBytes = new byte[]{ (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F };
return new AdvertiseData.Builder()
.addManufacturerData(manufacturerID, uuidBytes)
.setIncludeDeviceName(false)
.build();
}
Make sure you exclude the device name, some devices will put the advertising packet over the 31 bytes otherwise and it will fail to start advertising.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With