![](/img/trans.png)
[英]Android BLE: Successfully write ENABLE_NOTIFICATION_VALUE value to BluetoothGattDescriptor but onCharacteristicChanged never fires
[英]Android BLE: onCharacteristicChanged never fires
我正在尝试编写一个Android应用程序,模仿我编写的iOS应用程序中已存在的功能。 我正在与2个不同的BLE设备连接:
在iOS上,我有两个设备都运行良好并报告数据。 在Android上,我无法让它工作。 经过数小时的研究和测试,我认为我要解决的基本问题是:
在iOS上,我调用以下代码以使BLE设备在有数据要报告时通知我的iOS设备:
#pragma mark - CBPeripheralDelegate Protocol methods
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in [service characteristics]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
而已。 iOS中此方法的注释说明如下:
如果指定的特性配置为允许通知和指示,则调用此方法仅启用通知。
基于此(以及它在iOS中工作的事实),我正在计算我想要通知的特性的配置描述符应该像这样配置:
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
考虑到这一点,我的BLEDevice
类看起来像这样:
public abstract class BLEDevice {
protected BluetoothAdapter.LeScanCallback mLeScanCallback;
protected BluetoothGattCallback mBluetoothGattCallback;
protected byte[] mBytes;
protected Context mContext;
protected GotReadingCallback mGotReadingCallback;
protected String mDeviceName;
public final static UUID UUID_WEIGHT_SCALE_SERVICE
= UUID.fromString(GattAttributes.WEIGHT_SCALE_SERVICE);
public final static UUID UUID_WEIGHT_SCALE_READING_CHARACTERISTIC
= UUID.fromString(GattAttributes.WEIGHT_SCALE_READING_CHARACTERISTIC);
public final static UUID UUID_WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC
= UUID.fromString(GattAttributes.WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC);
public final static UUID UUID_WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR
= UUID.fromString(GattAttributes.WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR);
abstract void processReading();
interface GotReadingCallback {
void gotReading(Object reading);
}
public BLEDevice(Context context, String deviceName, GotReadingCallback gotReadingCallback) {
mContext = context;
BluetoothManager btManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
final BluetoothAdapter btAdapter = btManager.getAdapter();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mContext.startActivity(enableIntent);
}
mDeviceName = deviceName;
mBluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
byte[] data = characteristic.getValue();
mBytes = data;
Log.d("BluetoothGattCallback.onCharacteristicChanged", "data: " + data.toString());
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
// this will get called when a device connects or disconnects
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if (mBytes != null) {
processReading();
}
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d("onDescriptorWrite", "descriptor: " + descriptor.getUuid() + ". characteristic: " + descriptor.getCharacteristic().getUuid() + ". status: " + status);
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
BluetoothGattService service = gatt.getService(UUID_WEIGHT_SCALE_SERVICE);
if (service != null) {
BluetoothGattCharacteristic characteristic;
characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_READING_CHARACTERISTIC);
if (characteristic != null) {
gatt.setCharacteristicNotification(characteristic, true);
}
characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC);
if (characteristic != null) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID_WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR);
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
}
};
mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
Log.d("LeScanCallback", device.toString());
if (device.getName().contains("{Device Name}")) {
BluetoothGatt bluetoothGatt = device.connectGatt(mContext, false, mBluetoothGattCallback);
btAdapter.stopLeScan(mLeScanCallback);
}
}
};
btAdapter.startLeScan(mLeScanCallback);
}
}
注意:知道这两个设备以下列方式运行可能很重要:
- 打开BLE设备,在设备上启动测量。
- 一旦进行了测量,BLE设备就会尝试启动BLE连接。
- 一旦建立了BLE连接,设备就会立即发送数据,有时会发送一些数据包。 (如果以前的数据测量没有通过BLE成功发送,它会将它们保存在内存中并发送所有数据,所以我只关心最终的数据包。)
- 一旦发送了最终数据包,BLE设备就会快速断开连接。
- 如果BLE设备无法发送数据(如当前在Android应用程序上发生的那样),则BLE设备会非常快速地断开连接。
在我的LogCat中,我看到很多输出与我期望的完全一样。
我遇到的最新故障是onCharacteristicWrite
中报告的状态为“128”。 问题#3(下面)的评论似乎表明这是一个资源问题。
我看了下面的问题:
这就是为什么他们不给我我需要的东西:
我尝试过一些示例和教程,包括谷歌的Android示例代码。 他们似乎都没有让BLE设备通知我的Android设备数据更新。 它显然不是设备,因为iOS版本有效。 那么,iOS代码在后台做什么来使通知工作以及Android端的哪些代码将模仿该功能?
根据@ yonran的评论,我通过将onServicesDiscovered
实现更改为:更新了我的代码:
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
BluetoothGattService service = gatt.getService(UUID_WEIGHT_SCALE_SERVICE);
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_READING_CHARACTERISTIC);
if (characteristic != null) {
if (gatt.setCharacteristicNotification(characteristic, true) == true) {
Log.d("gatt.setCharacteristicNotification", "SUCCESS!");
} else {
Log.d("gatt.setCharacteristicNotification", "FAILURE!");
}
BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0);
if (0 != (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE)) {
// It's an indicate characteristic
Log.d("onServicesDiscovered", "Characteristic (" + characteristic.getUuid() + ") is INDICATE");
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
} else {
// It's a notify characteristic
Log.d("onServicesDiscovered", "Characteristic (" + characteristic.getUuid() + ") is NOTIFY");
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
}
}
这似乎确实改变了一些事情。 这是代码更改后的当前Logcat:
D/BluetoothGatt﹕ setCharacteristicNotification() - uuid: <UUID> enable: true
D/gatt.setCharacteristicNotification﹕ SUCCESS!
D/onServicesDiscovered﹕ Characteristic (<UUID>) is INDICATE
D/BluetoothGatt﹕ writeDescriptor() - uuid: 00002902-0000-1000-8000-00805f9b34fb
D/BluetoothGatt﹕ onDescriptorWrite() - Device=D0:5F:B8:01:6C:9E UUID=<UUID>
D/onDescriptorWrite﹕ descriptor: 00002902-0000-1000-8000-00805f9b34fb. characteristic: <UUID>. status: 0
D/BluetoothGatt﹕ onClientConnectionState() - status=0 clientIf=6 device=D0:5F:B8:01:6C:9E
所以,这样看来,我现在一切都设置正确(因为setCharacteristicNotification
返回true
和onDescriptorWrite
状态为0
)。 但是, onCharacteristicChanged
仍然永远不会发射。
我已经能够通过以下方式成功捕获具有多种服务和特征的onCharacteristicChanged():
在服务发现完成后,在主循环中的broadcastReceiver()中写入描述符值。
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() { //more code... if (action.equals(uartservice.ACTION_GATT_SERVICES_DISCOVERED)) { mService.enableTXNotification(); }
和
通过在描述符值设置之间添加延迟
public void enableTXNotification(){ /* if (mBluetoothGatt == null) { showMessage("mBluetoothGatt null" + mBluetoothGatt); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART); return; } */ /** * Enable Notifications for the IO service and characteristic * */ BluetoothGattService IOService = mBluetoothGatt.getService(IO_SERVICE_UUID); if (IOService == null) { showMessage("IO service not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_IO); return; } BluetoothGattCharacteristic IOChar = IOService.getCharacteristic(IO_CHAR_UUID); if (IOChar == null) { showMessage("IO charateristic not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_IO); return; } mBluetoothGatt.setCharacteristicNotification(IOChar,true); BluetoothGattDescriptor descriptorIO = IOChar.getDescriptor(CCCD); descriptorIO.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptorIO); /** * For some reason android (or the device) can't handle * writing one descriptor after another properly. Without * the delay only the first characteristic can be caught in * onCharacteristicChanged() method. */ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } /** * Enable Indications for the RXTX service and characteristic */ BluetoothGattService RxService = mBluetoothGatt.getService(RXTX_SERVICE_UUID); if (RxService == null) { showMessage("Rx service not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART); return; } BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RXTX_CHAR_UUID); if (RxChar == null) { showMessage("Tx charateristic not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART); return; } mBluetoothGatt.setCharacteristicNotification(RxChar,true); BluetoothGattDescriptor descriptor = RxChar.getDescriptor(CCCD); descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE ); mBluetoothGatt.writeDescriptor(descriptor); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } /** * Enable Notifications for the Battery service and Characteristic? */ BluetoothGattService batteryService = mBluetoothGatt.getService(BATTERY_SERVICE_UUID); if (batteryService == null) { showMessage("Battery service not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_BATTERY); return; } BluetoothGattCharacteristic batteryChar = batteryService.getCharacteristic(BATTERY_CHAR_UUID); if (batteryChar == null) { showMessage("Battery charateristic not found!"); broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_BATTERY); return; } }
我遇到了同样的问题。 这是因为当设备发送指示值时,您的应用程序将在另一个进程中收费,这就是为什么您永远不会获得使onCharacteristicChanged
永远不会触发的指示值的原因。 解决您的问题尝试将所有traitement放入服务中。 并且只需从您的活动中调用函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.