Android外设连接中央设备后无法主动发送消息求助
问题解决方案
核心原因
当onConnectionStateChange触发BluetoothProfile.STATE_CONNECTED时,蓝牙GATT仅完成了底层链路连接,中央设备还未完成服务发现和特征订阅流程。此时外设调用notifyCharacteristicChanged会因无有效订阅通道而失败。而中央设备先发消息的行为,说明它已经完成了服务发现与订阅,此时外设的通知通道才处于可用状态。
解决步骤
不要在连接建立回调中直接发消息,而是等待中央设备完成特征订阅的触发回调,再执行主动发消息逻辑:
- 监听
onDescriptorWriteRequest回调:该回调会在中央设备写入CLIENT_CHARACTERISTIC_CONFIG描述符时触发(这是蓝牙GATT订阅通知的标准操作)。 - 确认写入值为
ENABLE_NOTIFICATION_VALUE:此时说明中央设备已成功订阅目标特征,可安全调用notifyCharacteristicChanged发送消息。
代码示例
val callback = object : BluetoothGattServerCallback() { private var connectedDevice: BluetoothDevice? = null private var targetNotifyCharacteristic: BluetoothGattCharacteristic? = null // 假设已初始化gattServer实例 private val gattServer: BluetoothGattServer? = ... override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) { super.onConnectionStateChange(device, status, newState) when (newState) { BluetoothProfile.STATE_CONNECTED -> { connectedDevice = device // 仅记录连接设备,不执行消息发送 } BluetoothProfile.STATE_DISCONNECTED -> { connectedDevice = null targetNotifyCharacteristic = null } } } override fun onDescriptorWriteRequest( device: BluetoothDevice?, requestId: Int, descriptor: BluetoothGattDescriptor?, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray? ) { super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value) // 判断是否为订阅通知的描述符操作 if (descriptor?.uuid == BluetoothGattDescriptor.UUID_CLIENT_CHARACTERISTIC_CONFIG) { if (value?.contentEquals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) == true) { // 记录可通知特征,此时通道已就绪 targetNotifyCharacteristic = descriptor.characteristic // 主动发送连接成功消息 sendConnectionSuccessMessage() } } // 必须响应中央设备请求,否则可能导致后续通信异常 gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null) } private fun sendConnectionSuccessMessage() { connectedDevice?.let { device -> targetNotifyCharacteristic?.let { characteristic -> val messageBytes = "外设已连接".toByteArray(Charsets.UTF_8) characteristic.value = messageBytes // 第三个参数为false表示无需中央设备确认,可根据需求调整 gattServer?.notifyCharacteristicChanged(device, characteristic, false) } } } }
额外说明
- 固定延迟无效的原因:服务发现和订阅的耗时受设备性能、蓝牙环境影响,无固定值,硬编码延迟无法覆盖所有场景。
- 确保GATT特征已正确配置
PROPERTY_NOTIFY或PROPERTY_INDICATE属性,否则无法触发通知功能。
内容的提问来源于stack exchange,提问作者Amit Kar
相关产品推荐
相关产品推荐

