From 4fed5258ebb51bc590afea428e7307c8b64ff0ef Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Thu, 11 Jun 2026 21:48:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0ble?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunqiinnovation/ble_service/BleService.kt | 71 +++++++++++++------ 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index 2b410ea81..ee150730a 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -996,30 +996,48 @@ object BleService { isDescriptorWriteInProgress = false notificationTargetsTotal = 0 notificationTargetsSucceeded = 0 - if (callAudioChar != null && audioChar != null) { - setupNotifications(g, callAudioChar) - setupNotifications(g, audioChar) - Log.i(TAG, "通话音频服务特征找到并设置通知") - Handler(Looper.getMainLooper()).postDelayed({ - getDeviceWakeupVersion() - }, 1000) // 延迟3秒再请求版本,确保通知描述符写入完成 - } else { - Log.w(TAG, "通话音频服务特征未完整找到") - } - - setupNotifications(g, notifyChar) - - // 获取唤醒词OTA主服务特征 + // 获取唤醒词OTA主服务特征(提前获取,便于统一加入串行注册队列) val wakeupVoicesSvc = g.getService(BleConst.WakeupVoices_PRIMARY_SERVICE_UUID) wakeupVoicesNotifyChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_NOTIFY_UUID) wakeupVoicesWriteChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_WRITE_UUID) if (wakeupVoicesNotifyChar != null && wakeupVoicesWriteChar != null) { wakeupVoicesWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - setupWakeupVoicesNotifications(g, wakeupVoicesNotifyChar) Log.i(TAG, "liwei------- 唤醒词OTA服务特征已找到") - }else{ + } else { Log.w(TAG, "liwei------- 唤醒词OTA服务特征未找到") } + + // 串行注册所有需要通知/指示的特征: + // Android BLE 协议栈一次只允许一个 GATT 操作排队, + // 连续直接 writeDescriptor 会导致后续调用被丢弃,必须等上一个 onDescriptorWrite 回调后再写下一个。 + val notifyCandidates = listOf(callAudioChar, audioChar, notifyChar, wakeupVoicesNotifyChar) + for (c in notifyCandidates) { + if (c == null) continue + val supportsNotify = (c.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0 + val supportsIndicate = (c.properties and BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0 + val hasCccd = c.getDescriptor(BleConst.CLIENT_CHAR_CONFIG_UUID) != null + if ((supportsNotify || supportsIndicate) && hasCccd) { + notificationSetupQueue.addLast(c) + } else { + Log.w(TAG, "特征不支持通知/指示或缺少CCCD: ${c.uuid}") + } + } + notificationTargetsTotal = notificationSetupQueue.size + if (notificationTargetsTotal > 0) { + Log.i(TAG, "开始串行注册通知通道,总数: $notificationTargetsTotal") + processNextNotificationDescriptor(g) + } else { + Log.w(TAG, "未找到可注册通知/指示的特征") + } + + if (callAudioChar != null && audioChar != null) { + Log.i(TAG, "通话音频服务特征找到并加入通知注册队列") + Handler(Looper.getMainLooper()).postDelayed({ + getDeviceWakeupVersion() + }, 1500) // 适当放宽,确保所有CCCD串行写入完成 + } else { + Log.w(TAG, "通话音频服务特征未完整找到") + } // 在服务发现完成后,请求最大MTU //requestMaxMtu(g) @@ -1145,9 +1163,16 @@ object BleService { * @param characteristic 要设置通知的特征 */ private fun setupNotifications(g: BluetoothGatt, characteristic: BluetoothGattCharacteristic?) : Boolean{ - if (characteristic == null || characteristic.properties.and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0) { - Log.w(TAG, "特征不支持通知功能: ${characteristic?.uuid}") - return false + if (characteristic == null) { + Log.w(TAG, "特征为空,无法设置通知/指示") + return false + } + + val supportsNotify = characteristic.properties.and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0 + val supportsIndicate = characteristic.properties.and(BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0 + if (!supportsNotify && !supportsIndicate) { + Log.w(TAG, "特征不支持通知/指示功能: ${characteristic.uuid}") + return false } // 在本地启用特征通知监听 @@ -1165,8 +1190,12 @@ object BleService { return false } - // 设置描述符值为启用通知 - desc.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + // 设置描述符值:根据特征属性自适应启用 NOTIFY 或 INDICATE + desc.value = if (supportsNotify) { + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + } else { + BluetoothGattDescriptor.ENABLE_INDICATION_VALUE + } // 向远程设备写入描述符(异步操作,结果在onDescriptorWrite回调中处理) val writeResult = g.writeDescriptor(desc)