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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:15:36