You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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——这会导致:

  1. 服务端无法通过notifyCharacteristicChanged触发推送;
  2. 客户端写入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 17:25:30