From dd9e6ddf042daf5e9d8ba4b6200331712508e4e7 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Wed, 2 Jul 2025 22:16:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E8=AE=BE=E5=A4=87=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E7=A0=81=E8=87=AA=E5=8A=A8=E7=BB=91=E5=AE=9A=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=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 | 19 +++ .../controllers/pairing_controller.dart | 131 ++++++++++++------ .../yunqiinnovation/ble_service/BleService.kt | 26 +++- .../ble_service/BleServicePlugin.kt | 10 ++ .../ble_service/lib/ble_service.dart | 32 +++++ 5 files changed, 169 insertions(+), 49 deletions(-) diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index f379b53d8..42af34e4f 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -767,6 +767,25 @@ class BleManager extends GetxService { } } + /// 验证设备是否可以配对 + Future startScan() async { + try { + await _bleService.startScan(); + } catch (e) { + Logger.error('开始扫描设备: ${e.toString()}'); + } + } + + Future?> getDeviceInfo(String address) async { + try { + final result = _bleService.getDeviceInfo(address); + return result; + } catch (e) { + Logger.error('获取设备信息: ${e.toString()}'); + return null; + } + } + /// 验证设备是否可以配对 Future verifyDeviceCanPair(String macAddress) async { try { diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 0cd9fb15a..e06a8ed5a 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:app_settings/app_settings.dart'; import 'package:deep_voice/data/models/user_Info.dart'; import 'package:deep_voice/data/services/network/api.dart'; @@ -418,41 +421,32 @@ class PairingController extends GetxController { // TODO: 实现API验证逻辑 // 暂时模拟验证通过 // await Future.delayed(const Duration(seconds: 2));; - if (await authbindingDevice()) { - // 检查设备名称是否包含 DeepSound 或 DeapSound - final deviceName = device.name ?? ''; - if (deviceName.contains('DeepSound') || - deviceName.contains('DeapSound')) { - Logger.i(_tag, '设备验证通过'); - _verifiedDeviceAddress = device.address; - - // 检查是否已有BLE关联 - final pairedMacAddress = await _bleManager.getPairedMacAddress(); - Logger.i(_tag, '已关联的MAC地址: $pairedMacAddress'); - - if (pairedMacAddress != null && - pairedMacAddress.toUpperCase() == device.address.toUpperCase()) { - // 已有关联,检查BLE连接状态 - Logger.i(_tag, '设备已关联,检查BLE连接状态'); - final currentBleState = await _bleManager.getConnectionState(); - Logger.i(_tag, '验证时BLE状态: $currentBleState'); - - if (currentBleState == 2) { - // BleConnectionState.connected - Logger.i(_tag, 'BLE已连接,直接完成配对'); - _transition(PairingState.completed); - } else { - Logger.i(_tag, 'BLE未连接,等待BLE连接'); - _transition(PairingState.waitingBle); - } + if (await authbindingDevice(device)) { + Logger.i(_tag, '设备验证通过'); + _verifiedDeviceAddress = device.address; + // 检查是否已有BLE关联 + final pairedMacAddress = await _bleManager.getPairedMacAddress(); + Logger.i(_tag, '已关联的MAC地址: $pairedMacAddress'); + + if (pairedMacAddress != null && + pairedMacAddress.toUpperCase() == device.address.toUpperCase()) { + // 已有关联,检查BLE连接状态 + Logger.i(_tag, '设备已关联,检查BLE连接状态'); + final currentBleState = await _bleManager.getConnectionState(); + Logger.i(_tag, '验证时BLE状态: $currentBleState'); + + if (currentBleState == 2) { + // BleConnectionState.connected + Logger.i(_tag, 'BLE已连接,直接完成配对'); + _transition(PairingState.completed); } else { - // 没有关联或关联的是其他设备,需要进行关联 - Logger.i(_tag, '需要进行BLE设备关联'); - _transition(PairingState.associating); + Logger.i(_tag, 'BLE未连接,等待BLE连接'); + _transition(PairingState.waitingBle); } } else { - // _setError(ErrorType.deviceNotMatch, '请连接 DeepSound 设备'); - _transition(PairingState.completed); + // 没有关联或关联的是其他设备,需要进行关联 + Logger.i(_tag, '需要进行BLE设备关联'); + _transition(PairingState.associating); } } else { //验证失败 进入手动授权 @@ -531,27 +525,76 @@ class PairingController extends GetxController { } //自动绑定设备 - Future authbindingDevice() async { - if (User.instance.earphonemac == currentDevice?.address) { + Future authbindingDevice(BluetoothDevice device) async { + if (User.instance.earphonemac == device.address) { // 已经绑定 return true; } - // 调用BLE管理器的自动绑定方法 - final response = await Api.bindearphone({ - "earphonemac": currentDevice?.address, - }); - Logger.i(_tag, '手动授权结果 ${response}'); - if (response != null) { - Logger.i(_tag, '设备自动绑定成功'); - User.instance.earphonemac = currentDevice?.address ?? ''; - return true; + // 检查设备名称是否包含 DeepSound 或 DeapSound + final deviceName = device.name ?? ''; + print('获取到 deviceName: $deviceName'); + if (deviceName.contains('DeepSound') || deviceName.contains('DeapSound')) { + await _bleManager.startScan(); + // 尝试最多读取 3 次设备信息,每次间隔 1 秒 + Map? deviceinfo; + for (int i = 0; i < 3; i++) { + deviceinfo = await _bleManager.getDeviceInfo(device.address); + print('获取到 deviceinfo: $deviceinfo'); + if (deviceinfo != null) { + break; + } + await Future.delayed(Duration(seconds: 1)); + } + print('获取到 deviceinfo: $deviceinfo'); + if (deviceinfo != null) { + // final code = processHex(deviceinfo["hex"]!, 15, 25); + String code = extractAndReverseBytes(deviceinfo["hex"]!, 15, 24); + print('获取到 code: $code'); + // 安全检查长度 + if (code != "") { + final response = await Api.bindearphone({ + "code": code, + "earphonemac": device.address, + }); + Logger.i(_tag, '手动授权结果 ${response}'); + if (response != null) { + Logger.i(_tag, '设备自动绑定成功'); + User.instance.earphonemac = device.address ?? ''; + return true; + } else { + Logger.e(_tag, '手动绑定失败!'); + return false; + } + } else { + return false; + } + } + return false; + // 调用BLE管理器的自动绑定方法 } else { - Logger.e(_tag, '手动绑定失败!'); return false; } } + int reverseBits(int byte) { + // 这里是 nibble swap 还是 bit 反转?看你需求,先保持 nibble swap + return ((byte & 0x0F) << 4) | ((byte & 0xF0) >> 4); + } + + String extractAndReverseBytes(String hex, int start, int end) { + List bytes = []; + for (int i = 0; i < hex.length; i += 2) { + bytes.add(int.parse(hex.substring(i, i + 2), radix: 16)); + } + List slice = bytes.sublist(start, end + 1); + List reversed = slice.reversed.toList(); + return reversed + .map((b) => b.toRadixString(16).padLeft(2, '0')) + .join() + .toUpperCase(); + } + /// 用户点击授权码输入框 void onAutoCodeInputTap() async { // 调用BLE管理器的自动绑定方法 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 70c58d3d0..b2fbe0cab 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 @@ -298,32 +298,48 @@ object BleService { } } + fun getDeviceInfo(address: String): Map? { + + // 更新缓存 + val idx = scanResults.indexOfFirst { it.device.address == address } + Log.d(TAG, "获取设备信息:${address} idx:$idx") + if (idx >= 0){ + val result = scanResults[idx]; + return printDeviceInfo(result) + } + return null; + } + /** * 打印设备信息和服务UUID */ - private fun printDeviceInfo(result: ScanResult) { + private fun printDeviceInfo(result: ScanResult):Map?{ val device = result.device val scanRecord = result.scanRecord val serviceUuids = scanRecord?.serviceUuids?.joinToString(", ") { it.uuid.toString() } ?: "无" Log.d( - TAG, "扫描到设备: 名称=${device.name ?: "未知"}, 地址=${device.address}, " + + TAG, "liwei--------- 扫描到设备: 名称=${device.name ?: "未知"}, 地址=${device.address}, " + "RSSI=${result.rssi}, 服务UUID=[$serviceUuids]" ) - + val info = mutableMapOf( + "name" to (device.name ?: "未知"), + "address" to device.address + ) // 打印广播数据的详细信息 val scanData = scanRecord?.bytes if (scanData != null) { val hexString = scanData.joinToString("") { String.format("%02X", it) } - Log.d(TAG, "广播数据: $hexString") - + Log.d(TAG, "liwei------------ 广播数据: $hexString") + info["hex"] = hexString // 解析服务数据 scanRecord.serviceData?.forEach { (uuid, data) -> val dataHex = data.joinToString("") { String.format("%02X", it) } Log.d(TAG, "服务数据: UUID=${uuid.uuid}, 数据=$dataHex") } } + return info } // ====================================================================================================== diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt index 07f3ab396..3e5062717 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt @@ -294,6 +294,16 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, result.error("UNSUPPORTED", "设备不支持Companion Device Manager", null) } } + "startScan" -> { + val connected = BleService.startScan() + result.success(connected) + } + "getDeviceInfo" -> { + val address = call.argument("address")?:"" + val info = BleService.getDeviceInfo(address); + Log.d(TAG, "getDeviceInfo $info") + result.success(info) + } else -> { result.notImplemented() } diff --git a/local_plugins/ble_service/lib/ble_service.dart b/local_plugins/ble_service/lib/ble_service.dart index ad11aa617..956e3a28e 100644 --- a/local_plugins/ble_service/lib/ble_service.dart +++ b/local_plugins/ble_service/lib/ble_service.dart @@ -281,6 +281,38 @@ class BleService { } } + /// 断开连接 + Future startScan() async { + try { + final result = await _methodChannel.invokeMethod('startScan'); + return result ?? false; + } catch (e) { + print('开启扫描ble设备失败: $e'); + return false; + } + } + + /// 断开连接 + Future?> getDeviceInfo(String address) async { + try { + final result = await _methodChannel + .invokeMethod('getDeviceInfo', {'address': address}); + print('获取设备信息!: $result'); + if (result != null) { + return { + 'name': result['name'] ?? "未知", + 'address': result['address'] ?? "", + 'hex': result['hex'] ?? "", + }; + } else { + return null; + } + } catch (e) { + print('获取设备信息失败!: $e'); + return null; + } + } + /// 注册BLE后台扫描 /// /// 注册后,即使应用被杀死,系统也会在检测到设备广播时唤醒应用