Android 12设备BLE GATT解绑后重连失败,卡在BluetoothSocket.connect()
Android 12部分设备BLE解绑后重连,BluetoothSocket.connect()阻塞卡死
问题描述
开发基于Android BLE GATT的功能,绑定由系统自动处理,未主动调用createBond()。在部分Android 12设备(三星A系列One UI 4.1、部分Pixel设备)出现异常:
- 首次配对连接完全正常
- 通过反射调用
removeBond()解绑后再次重连,设备能重新配对,但调用BluetoothSocket.connect()会阻塞卡死 - 由于
connect()是阻塞方法且无回调,无法执行后续重连逻辑 - 相同场景在Android 13设备(Pixel 7 Pro/Samsung S22 Ultra)上运行正常
尝试过多种重连、重新绑定方式均无效,了解到Android 12 AOSP中将GATT监管时间调整为5秒,但问题依旧存在。
相关代码
创建L2Cap通道
fun createL2CapChannel(bluetoothDevice: BluetoothDevice, psmInt: Int): BluetoothSocket { if (socket == null) { Log.d(TAG, "Creating L2Cap channel") socket = bluetoothDevice.createL2capChannel(psmInt) } return socket as BluetoothSocket }
Socket连接逻辑
fun connectToBluetoothSocket() { if (socket!!.isConnected) { Log.d(TAG, "L2Cap Socket connected") } else { Log.d(TAG, "L2Cap Socket connecting") socket!!.connect() } }
重连时会卡在socket!!.connect()行
断开Gatt连接逻辑
fun disconnectGattServer() { if (bleGatt != null) { Log.d(TAG, "Closing Gatt") bleGatt?.disconnect() bleGatt?.close() bleGatt = null } }
可行解决方向
禁用Socket实例复用
解绑重连时,不要复用之前创建的BluetoothSocket,每次重连都重新调用bluetoothDevice.createL2capChannel(psmInt)生成新实例。旧实例可能残留配对状态信息,导致Android 12蓝牙服务处理异常。完善解绑后的清理流程
解绑后除了处理Gatt连接,还要确保蓝牙资源完全释放:- 通过反射调用
BluetoothDevice.cancelBondProcess(),确保系统彻底清除配对缓存 - 调用
BluetoothAdapter.cancelDiscovery()停止扫描操作 - 延迟1-2秒再发起重连,给系统足够时间清理配对状态
- 通过反射调用
给connect()添加超时中断
针对connect()阻塞无回调的问题,用线程配合超时机制强制中断:fun connectWithTimeout(socket: BluetoothSocket, timeoutMs: Long = 10000): Boolean { val connectThread = Thread { try { socket.connect() } catch (e: Exception) { // 捕获连接异常 } } connectThread.start() connectThread.join(timeoutMs) return socket.isConnected }超时后若未连接成功,销毁当前Socket并创建新实例重试。
主动触发配对而非依赖系统自动处理
重连前主动调用bluetoothDevice.createBond()触发配对,绕过Android 12部分设备的系统自动配对逻辑缺陷。重启蓝牙服务(激进方案)
若上述方法无效,可尝试重启蓝牙服务(需用户授权),解决系统蓝牙服务的异常状态:fun restartBluetooth(adapter: BluetoothAdapter) { adapter.disable() while (adapter.isEnabled) { Thread.sleep(100) } adapter.enable() }
内容的提问来源于stack exchange,提问作者Rishabh Gupta
相关产品推荐
相关产品推荐

