From a4b3cbf8a97b5bf2837373b24de2aad5e7eb8343 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Sat, 9 May 2026 16:47:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=94=B5=E9=87=8F=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/services/ble_manager.dart | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index a2991b6cf..7c7477378 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -189,6 +189,7 @@ class BleManager extends GetxService { print('[BLE] BleManager 构造,立即启动杰理 SDK 初始化'); _initFuture = _initializeJieli(); _setupEventListener(); + _startConnectionWatchdog(); } @override @@ -201,6 +202,7 @@ class BleManager extends GetxService { void onClose() { _eventSub?.cancel(); _stopBatteryWatchdog(); + _stopConnectionWatchdog(); _callTranslationRequestController.close(); _inUplinkPcmController.close(); _inDownlinkPcmController.close(); @@ -380,6 +382,83 @@ class BleManager extends GetxService { _batteryWatchdog = null; } + // 连接状态 watchdog:杰理 SDK 在某些时序下不会回调 ConnectionStateEvent + // (冷启时设备已经连着、事件订阅 race、原生侧自动重连等),导致本地 Rx + // 状态停在 disconnected 但 SDK 内部已经有连接。这里定期直接问 SDK。 + // + // 重要:只做"单向"同步(disconnected → connected),**不**把已连状态翻回 + // disconnected。原因:multi-device 模式下 connectedDevice() 偶发会返回 null, + // 上一版把它当真翻成 disconnected 反而把已连接 UI 抹掉了。断开仍走 + // ConnectionStateEvent.connectionDisconnect 那条事件路径。 + Timer? _connectionWatchdog; + static const Duration _connectionWatchdogInterval = Duration(seconds: 5); + + void _startConnectionWatchdog() { + _connectionWatchdog?.cancel(); + _connectionWatchdog = Timer.periodic(_connectionWatchdogInterval, (_) { + _reconcileConnectionFromSdk(); + }); + } + + void _stopConnectionWatchdog() { + _connectionWatchdog?.cancel(); + _connectionWatchdog = null; + } + + Future _reconcileConnectionFromSdk() async { + if (!_initSucceeded) return; + try { + // 步骤 1:尽量找到一个真实在连的 address。 + // 优先:本地已有 currentDeviceAddress → 直接 isConnected(addr) 校验。 + // 兜底:connectedDevice() 看 SDK 是否能给出当前已连设备。 + String? sdkConnectedAddr; + String? sdkConnectedName; + final localAddr = currentDeviceAddress; + if (localAddr != null && localAddr.isNotEmpty) { + if (await Jielihome.instance.isConnected(localAddr)) { + sdkConnectedAddr = localAddr; + sdkConnectedName = _currentDeviceName; + } + } + if (sdkConnectedAddr == null) { + final dev = await Jielihome.instance.connectedDevice(); + if (dev != null && dev.address.isNotEmpty) { + sdkConnectedAddr = dev.address; + sdkConnectedName = dev.name; + } + } + + if (sdkConnectedAddr == null) return; // 没拿到,本轮放弃,**不**翻 _isConnected + + // 步骤 2:本地 Rx 与 SDK 不一致 → 强制同步到「已连」。 + final wasConnected = _isConnected.value; + final addressChanged = currentDeviceAddress != sdkConnectedAddr; + if (!wasConnected || addressChanged) { + Logger.w('BleManager', + '[WATCHDOG] 本地 isConnected=$wasConnected addr=$currentDeviceAddress' + ' / SDK 在连 $sdkConnectedAddr → 同步为 connected'); + currentDeviceAddress = sdkConnectedAddr; + if (sdkConnectedName != null && sdkConnectedName.isNotEmpty) { + _currentDeviceName = sdkConnectedName; + } + _isConnected.value = true; + _connectionState.value = BleConnectionState.connected; + _ensureDeviceInfoStub(); + } + + // 步骤 3:兜底电量。冷启场景下 RcspInitEvent 不会再来, + // _startBatteryWatchdog 永远不被触发,电量 UI 一直 0。 + // 这里发现 SDK 在连且本地电量为 0 时,主动启动一次电量轮询。 + final lvl = deviceInfo.value?.batteryLevel ?? 0; + if (lvl == 0 && _batteryWatchdog == null) { + Logger.i('BleManager', '[WATCHDOG] 已连但电量=0,启动电量轮询补抓'); + _startBatteryWatchdog(); + } + } catch (e) { + Logger.w('BleManager', '[WATCHDOG] 查询 SDK 连接状态失败: $e'); + } + } + void _handleBattery(BatteryEvent e) { final level = e.level ?? 0; _ensureDeviceInfoStub();