1

I am an iOS developer building my first Android bluetooth app. In my app I have two classes, one main class that calls a second that is my BluetoothGattCallback.

After I scan for devices, I find the one I want, connect to it. This all works. My bluetooth device transmits data every 5 seconds, so far I can only get first byteArray transmission. Here is what I call in my main class.

val gatt = device?.connectGatt(context, true, callBack)

Then in onConnectionStateChange I check that it has made a connection and call gatt?.discoverServices(). From there I can filter the UUID's in onServicesDiscovered and call gatt.readCharacteristic(characteristic). I am finally able to read my byte data in onCharacteristicRead. My question is, what step did I miss to get new data upon each transmission after the device is connected?

Bonus question: How would I manage multiple device call backs? If I try and connect more than one device, do I need to keep a reference to each instance of my callback or BluetoothGatt with that device?

4

1 回答 1

1

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
    }
}
于 2018-06-21T21:55:02.740 回答