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

一加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:40:37