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

Android BLE连接时同时调用requestMtu()与discoverServices(),对接主动发起MTU协商的外设导致onServicesDiscovered()不触发的兼容性问题

Android BLE连接时同时调用requestMtu()与discoverServices(),对接主动发起MTU协商的外设导致onServicesDiscovered()不触发的兼容性问题

最近踩了个Android BLE的兼容性大坑,跟大家唠唠排查过程和解决办法,应该能帮到碰到同类问题的朋友。

我这边是用compileSDK=35的Android设备做BLE中心端,连接一个有点特殊的外设——这货明明是服务器角色,却偏要主动发起MTU协商。最开始写的代码是设备连接成功后,同时调用gatt.requestMtu(512)和gatt.discoverServices(),结果直接卡壳:服务发现完全停滞,onServicesDiscovered()回调根本不触发。

先给大家看最开始出问题的代码:

override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
        when (newState) {
            BluetoothProfile.STATE_CONNECTED -> {
                // 同时发起MTU协商和服务发现,这里就是坑点
                gatt.requestMtu(512)
                gatt.discoverServices()
            }
            BluetoothProfile.STATE_DISCONNECTED -> {
                // 断开连接后的清理逻辑
            }
        }
    }
}

override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
        // 发现服务后开启通知等逻辑,根本走不到这
        . . .
    }
}

为了定位问题,我做了几个测试:

  • 把gatt.requestMtu(512)这行删掉,服务发现立刻正常,但这样其他不会主动发起MTU协商的外设就没法用了,显然不是长久之计;
  • 让外设那边关掉主动发起MTU协商的功能,问题也消失,但总不能要求所有合作的外设都改配置吧;
  • 对比了两种场景的Android Studio日志:
    • 外设主动发起MTU时:日志最后只到onConfigureMTU(),onSearchComplete和onServicesDiscovered的日志完全没出现;
    • 外设关掉主动MTU后:onConfigureMTU()之后马上就出现了onSearchComplete()和onServicesDiscovered()的日志,后续逻辑全部正常执行。

最后试了个调整时机的办法,居然解决了:把MTU协商的调用从连接成功时,挪到服务发现成功之后,也就是在onServicesDiscovered()里调用requestMtu()。

修改后的代码是这样的:

override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
        when (newState) {
            BluetoothProfile.STATE_CONNECTED -> {
                // 先只做服务发现
                gatt.discoverServices()
            }
            BluetoothProfile.STATE_DISCONNECTED -> {
                // 断开连接后的清理逻辑
            }
        }
    }
}

override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
        // 服务发现成功后,再发起MTU协商
        gatt.requestMtu(512)
        // 这里正常处理服务相关逻辑,比如开启特征通知等
        . . .
    }
}

后来琢磨了下原因,应该是当外设和Android端同时发起MTU协商时,BLE链路的命令队列发生了冲突,服务发现的请求被MTU协商的双向交互给阻塞或者覆盖了。而先等服务发现完成再发起MTU协商,就能避开这种命令竞争的情况——不管外设会不会主动发起MTU协商,链路此时已经稳定,不会再出现回调丢失的问题,兼容性拉满。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:27:59