一加Nord(Android 12)BLE智能手环发指令即断开问题求助
BLE手环在一加Nord(Android 12)发送指令后自动断开连接问题排查与解决方案
问题描述
我有一款BLE智能手环,可与安卓APP配对通信,通过向不同特征值发送指令获取数据,该功能在多数最新安卓版本手机上运行正常。但在一加Nord(Android 12)上出现异常:手环能正常配对,但发送指令后1秒内自动断开连接;不发送指令时连接稳定。同款手环在其他安卓机型上无此问题,仅约5%的安卓设备存在该现象。
已尝试的解决方法
- 重置手机网络与蓝牙
- 清除系统蓝牙应用缓存
- 在手环端调整连接间隔、从机延迟与监管超时
关键测试观察与代码
手环定义了多个接收数据的UUID,APP会为这些UUID启用通知,当特征值字节变化时触发通知。相关实现代码如下:
fun queueSetNotificationForCharacteristic( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic ) { val ghattQueueItem = GhattQueueItem( characteristic = characteristic, enabled = true, ghatt = gatt, ghattQueueItemType = SUBSCRIBE_CHARACTERISTIC ) setNotificationForCharacteristic(ghattQueueItem) } private fun setNotificationForCharacteristic(ghattQueueItem: GhattQueueItem) { ghattQueueItem.ghatt?.let { gatt -> ghattQueueItem.characteristic?.let { characteristic -> gatt.setCharacteristicNotification(characteristic, true) // This is specific to Heart Rate Measurement. val descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){ gatt.writeDescriptor(descriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) }else{ descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE gatt.writeDescriptor(descriptor) } } } }
进一步测试发现:在一加Nord设备上,先发送指令再启用通知,手环可保持连接;但先启用通知再发送指令,会触发断开。该流程在多数安卓设备上正常,仅此机型异常。
解决方案建议
1. 针对特殊机型适配操作顺序
检测到一加Nord(Android 12)时,强制采用「先发送指令再启用通知」的流程,通过设备信息判断触发适配:
val isOnePlusNordAndroid12 = Build.MANUFACTURER.equals("OnePlus", ignoreCase = true) && Build.MODEL.equals("Nord", ignoreCase = true) && Build.VERSION.SDK_INT == Build.VERSION_CODES.S if (isOnePlusNordAndroid12) { // 先执行指令发送逻辑,需等待写入回调确认完成 sendCommandToCharacteristic(gatt, commandCharacteristic) } else { // 原有正常流程:先启用通知再发送指令 queueSetNotificationForCharacteristic(gatt, notificationCharacteristic) sendCommandToCharacteristic(gatt, commandCharacteristic) } // 在BluetoothGattCallback的onCharacteristicWrite回调中触发通知启用 override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS && isOnePlusNordAndroid12) { queueSetNotificationForCharacteristic(gatt!!, notificationCharacteristic) } }
2. 实现GATT操作串行队列
将所有BLE操作(写特征值、写描述符、启用通知)放入串行队列执行,避免并发操作导致的BLE栈混乱:
private val gattOperationQueue = LinkedList<GhattQueueItem>() private var isProcessingQueue = false fun queueSetNotificationForCharacteristic(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) { val item = GhattQueueItem( characteristic = characteristic, enabled = true, ghatt = gatt, ghattQueueItemType = SUBSCRIBE_CHARACTERISTIC ) gattOperationQueue.add(item) processQueueIfIdle() } fun queueWriteCharacteristic(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) { val item = GhattQueueItem( characteristic = characteristic, value = value, ghatt = gatt, ghattQueueItemType = WRITE_CHARACTERISTIC ) gattOperationQueue.add(item) processQueueIfIdle() } private fun processQueueIfIdle() { if (isProcessingQueue || gattOperationQueue.isEmpty()) return isProcessingQueue = true val nextItem = gattOperationQueue.removeFirst() when (nextItem.ghattQueueItemType) { SUBSCRIBE_CHARACTERISTIC -> setNotificationForCharacteristic(nextItem) WRITE_CHARACTERISTIC -> nextItem.ghatt?.writeCharacteristic(nextItem.characteristic) } } // 在GATT回调中触发下一个操作 override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) { super.onDescriptorWrite(gatt, descriptor, status) if (status == BluetoothGatt.GATT_SUCCESS) { isProcessingQueue = false processQueueIfIdle() } } override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { isProcessingQueue = false processQueueIfIdle() } }
3. 确保通知配置完成后再发送指令
在onDescriptorWrite回调中确认描述符写入成功后,再执行指令发送逻辑,避免BLE栈状态不一致:
private var isNotificationConfigured = false override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) { super.onDescriptorWrite(gatt, descriptor, status) if (status == BluetoothGatt.GATT_SUCCESS && descriptor?.uuid == UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")) { isNotificationConfigured = true // 通知配置完成后发送指令 sendCommandToCharacteristic(gatt!!, commandCharacteristic) } }
内容的提问来源于stack exchange,提问作者Dnveeraj
相关产品推荐
相关产品推荐

