Bluetooth GATT requires that centrals subscribe to receive "notifications" of characteristic changes. Upon connecting to the peripheral (after services have been discovered) you need to subscribe to the characteristic. When an Android central receives a notification (from the peripheral) the onCharacteristicChanged
function of the BluetoothGattCallback is called (unlike on iOS where characteristicRead is called both for notifications and manually requested reads). Unfortunately, on Android subscribing to a characteristic is more complicated than on iOS. On iOS a CBPeripheral has the setNotifyValue
function. An android BluetoothDevice object has no such function. I use this function, which does the same thing as iOS's setNotifyValue
, in my Android apps.
/**
* Subscribe to a characteristic to receive notifications when is's value is changed
* @param gattConnection Which gattConnection to subscribe to characteristic on
* @param characteristic The characteristic to subscribe to
* @param subscribe Whether not to subscribe to the characteristic (false to unsubscribe)
*/
fun subscribeToCharacteristic(gattConnection: BluetoothGatt, characteristic: BluetoothGattCharacteristic, subscribe: Boolean = true) {
gattConnection.setCharacteristicNotification(char, subscribe) // Tell the connection we intend to subscribe or unsubscribe
// Now write the correct value to the client characteristic config descriptor
val descriptor = char.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")) // Client characteristic config UUID
if(descriptor != null){
descriptor.value = if(subscribe) BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE else BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
gattConnection?.writeDescriptor(descriptor)
}
}
Just use the above function to subscribe to characteristic
in onServicesDiscovered
.
In response to handling multiple connections:
Multiple BluetoothGattCallback
's are not necessary. All you need to keep track of is the BluetoothGatt
objects returned from the connectGatt
function. Each function in BluetoothGattCallback has a BluetoothGatt
object as its first parameter. Just compare the BluetoothGatt
object that was passed to the function to the BluetoothGatt
objects returned from connectGatt
to determine which connection the event is from.
For example:
// This is in the BluetoothGattCallback
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
if(gatt === gattConnection1){
// This event came from the first connection
}else if(gatt === gattConnection2){
// This event came from the second connection
}
}