Android BluetoothGatt切换设备模式后无法发现更新服务的解决方法
Android端BLE Gatt服务缓存重置方案(适配Flutter+STM32场景)
问题场景
我正在开发一款Flutter应用,通过蓝牙与STM32单片机通信。该单片机有两个基于BLE协议栈的固件,对应不同Gatt Profile:
- Normal(应用)固件:包含多种服务UUID
- Firmware Update固件:仅包含OTA服务UUID
设备运行Normal固件时,Firmware Update服务及特征不可用;切换到Firmware Update模式时,设备会重启,Normal服务及特征被隐藏。设备已与Android应用配对/绑定,切换模式后Android端会重新调用Gatt发现服务,但Android在配对阶段会缓存服务和特征,导致获取到的仍是旧缓存内容,而非更新后的服务。
已尝试的无效方法
- 调用BluetoothGatt的私有refresh方法,当前版本无法实现
- 执行
BluetoothGatt.disconnect()->BluetoothGatt.close()-> 将BluetoothGatt置空 -> 重新调用connect gatt - 监听通用属性服务(Generic Attribute)中的服务变更特征(Service Changed),设置特征通知为true并配置CCC描述符值
可行的缓存重置方案
1. 清除系统配对记录(兜底方案)
在Android系统设置中找到目标蓝牙设备,删除配对记录后重新搜索配对。此方法能彻底清除系统层面的Gatt缓存,但操作对用户不友好,适合调试阶段使用。
2. 反射调用系统API清除绑定
通过Android原生代码反射调用BluetoothDevice的removeBond()方法清除设备绑定,再重新连接。Flutter端需通过MethodChannel调用原生代码,示例如下:
// Android原生代码片段 BluetoothDevice targetDevice = ...; // 获取目标蓝牙设备实例 try { Method removeBondMethod = BluetoothDevice.class.getMethod("removeBond"); removeBondMethod.invoke(targetDevice); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); }
清除绑定后重新连接,系统会重新发现设备服务,不会复用旧缓存。
3. 优化STM32端Service Changed特征实现
确保STM32在固件切换重启后,主动向已绑定的Android设备发送Service Changed通知:
- 设备需支持Generic Attribute服务中的Service Changed特征(UUID:
00002a05-0000-1000-8000-00805f9b34fb) - 切换固件后,设备主动推送该特征的通知,内容包含服务变更的起始和结束句柄
Android系统收到该通知后,会自动触发Gatt服务重新发现并更新本地缓存。
4. 利用Flutter BLE插件的内置缓存清理
使用flutter_blue_plus等成熟BLE插件时,调用插件提供的缓存清理方法,示例:
// flutter_blue_plus插件示例代码 await targetDevice.clearGattCache(); await targetDevice.connect();
内容的提问来源于stack exchange,提问作者zainhassan
相关产品推荐
相关产品推荐

