Android端BLE服务端与客户端通知订阅问题及排查
Android BLE服务端向客户端推送特征更新通知问题排查与修复
问题1:订阅代码的部署位置
这段代码必须部署在客户端。BLE通知机制的逻辑是:
- 客户端调用
setCharacteristicNotification(true)开启本地的通知监听开关; - 客户端通过写入CCCD(Client Characteristic Configuration Descriptor)告知服务端:需要接收该特征的更新通知。
服务端无需执行这部分代码,仅需在特征有更新时调用notifyCharacteristicChanged完成推送即可。
问题2:手动添加CCCD描述符的可行性
可以手动添加CCCD描述符,但有个核心前提:对应的特征必须具备PROPERTY_NOTIFY或PROPERTY_INDICATE属性。这两个属性是BLE通知/指示功能的标识,缺少它们的话,即使添加了CCCD,服务端也无法向客户端推送通知。
后续尝试的异常分析与修复
你遇到的双向通信异常,核心问题出在服务端特征的属性配置上:
核心问题点
服务端创建特征时,仅设置了PROPERTY_WRITE和PROPERTY_WRITE_NO_RESPONSE属性,缺少关键的PROPERTY_NOTIFY;同时特征权限仅配置了PERMISSION_WRITE,未添加PERMISSION_READ——这会导致:
- 服务端无法通过
notifyCharacteristicChanged触发推送; - 客户端写入CCCD后,因特征不具备通知属性,触发GATT链路异常,最终导致双向通信失效。
修复步骤
1. 修改服务端特征配置
更新generateGattService中的特征创建代码,补充通知属性和读权限:
private fun generateGattService(): BluetoothGattService { val service = BluetoothGattService(GAME_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY) characteristic = BluetoothGattCharacteristic( MESSAGE_UUID, // 补充PROPERTY_NOTIFY属性 BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or BluetoothGattCharacteristic.PROPERTY_NOTIFY, // 补充PERMISSION_READ权限 BluetoothGattCharacteristic.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ ) val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") val cccd = BluetoothGattDescriptor( CCC_DESCRIPTOR_UUID, BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE ) characteristic!!.addDescriptor(cccd) service.addCharacteristic(characteristic) return service }
2. 恢复客户端CCCD写入逻辑
取消客户端写入CCCD的注释,确保通知订阅流程完整:
private fun onConnected(discoveredGatt: BluetoothGatt){ val service = discoveredGatt.getService(GAME_UUID) val messageCharacteristic = service.getCharacteristic(MESSAGE_UUID) discoveredGatt.setCharacteristicNotification(messageCharacteristic, true) val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") val desc = messageCharacteristic.getDescriptor(CCC_DESCRIPTOR_UUID) desc.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE discoveredGatt.writeDescriptor(desc) Log.i(TAG_CLIENT, "Connected C -> S") }
3. 确认服务端推送逻辑参数
服务端调用notifyCharacteristicChanged时,第三个参数保持false(对应无需确认的通知模式),确保特征值已正确赋值:
characteristic.value = msg // false对应NOTIFY模式,true对应需要客户端确认的INDICATE模式 gattServer.notifyCharacteristicChanged(deviceToNotify, characteristic, false)
额外注意事项
- BLE GATT操作是异步的,所有写入/读取操作都需要在对应的回调(
onDescriptorWrite、onCharacteristicWrite等)中确认执行成功后,再进行后续操作; - 客户端需要在
onCharacteristicChanged回调中接收服务端推送的特征更新。
内容的提问来源于stack exchange,提问作者ilya_kas
相关产品推荐
相关产品推荐

