From f24cc654b84aacbd04a1e9134a2ff5498b1e1f79 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Wed, 16 Jul 2025 12:01:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=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 | 14 +- .../controllers/pairing_controller.dart | 170 ++++++++++--- .../Sources/ble_service/BleService.swift | 240 +++++++++++++----- .../ble_service/SwiftBleServicePlugin.swift | 14 +- .../ble_service/lib/ble_service.dart | 38 ++- 5 files changed, 368 insertions(+), 108 deletions(-) diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index 30c247463..329604300 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -782,9 +782,19 @@ class BleManager extends GetxService { } } - Future?> getDeviceInfo(String address) async { + Future?> getDeviceInfo(String deviceName) async { try { - final result = _bleService.getDeviceInfo(address); + final result = _bleService.getDeviceInfo(deviceName); + return result; + } catch (e) { + Logger.error('获取设备信息: ${e.toString()}'); + return null; + } + } + + Future>?> getDeviceList(String deviceName) async { + try { + final result = _bleService.getDeviceList(deviceName); return result; } catch (e) { Logger.error('获取设备信息: ${e.toString()}'); diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 2c31301aa..406100f5b 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 '/data/models/appconfig.dart'; import '/data/models/user_Info.dart'; @@ -11,6 +14,7 @@ import '../../../core/utils/logger.dart'; import 'dart:io'; import '../../../data/services/bluetooth_manager.dart'; import '../../../data/services/ble_manager.dart'; +import '../../../core/utils/permission_util.dart'; /// 配对状态枚举 - 简化版本 enum PairingState { @@ -414,16 +418,34 @@ class PairingController extends GetxController { /// 检查权限 Future _checkPermissions() async { - // Android 平台权限检查 - Map statuses = await [ - Permission.bluetoothScan, - Permission.bluetoothConnect, - Permission.locationWhenInUse, - ].request(); + // Android权限检查 + if (Platform.isAndroid) { + Logger.i(_tag, '开始检查Android权限'); + // 检查蓝牙相关权限 + final bluetoothScanGranted = + await PermissionUtil.instance.requestPermission( + permissionType: Permission.bluetoothScan, + permissionName: 'bluetoothScan'.tr, + explanationText: 'bluetoothScanExplanation'.tr, + permanentDenialText: 'bluetoothScanPermanentDenial'.tr, + ); + final bluetoothConnectGranted = + await PermissionUtil.instance.requestPermission( + permissionType: Permission.bluetoothConnect, + permissionName: 'bluetoothConnect'.tr, + explanationText: 'bluetoothConnectExplanation'.tr, + permanentDenialText: 'bluetoothConnectPermanentDenial'.tr, + ); + final locationGranted = await PermissionUtil.instance.requestPermission( + permissionType: Permission.locationWhenInUse, + permissionName: 'locationInfo'.tr, + explanationText: 'locationForBluetoothExplanation'.tr, + permanentDenialText: 'locationPermanentDenial'.tr, + ); - return statuses[Permission.bluetoothScan]!.isGranted && - statuses[Permission.bluetoothConnect]!.isGranted && - statuses[Permission.locationWhenInUse]!.isGranted; + return bluetoothScanGranted && bluetoothConnectGranted && locationGranted; + } + return true; } /// 验证设备 @@ -566,13 +588,8 @@ class PairingController extends GetxController { //自动绑定设备 0 未合作商 1 合作商 2,已绑定 Future authbindingDevice(BluetoothDevice device) async { - if (User.instance.earphonelicense != "" && - User.instance.earphonemac == device.address) { - // 已经绑定 - return 10; - } - if (User.instance.earphoneauthcode != "" && - User.instance.earphonemac == device.address) { + // 检查是否已经绑定 + if (User.instance.earphonemac == device.address) { // 已经绑定 return 9; } @@ -580,51 +597,124 @@ class PairingController extends GetxController { final deviceName = device.name; final names = AppConfig.allproductNames(); - print('获取到 deviceName: $deviceName names:$names'); + print( + '获取到 deviceName: $deviceName address: ${device.address} names:$names'); if (names.contains(deviceName)) { await _bleManager.startScan(deviceName); await Future.delayed(const Duration(seconds: 1)); // 尝试最多读取 3 次设备信息,每次间隔 1 秒 - Map? deviceinfo; + List>? deviceinfos; for (int i = 0; i < 3; i++) { - deviceinfo = await _bleManager.getDeviceInfo(device.address); - print('获取到 deviceinfo: $deviceinfo'); - if (deviceinfo != null) { - break; + // 使用设备名称获取设备列表 + deviceinfos = await _bleManager.getDeviceList(deviceName); + print('获取到 deviceinfos: $deviceinfos'); + + if (deviceinfos != null && deviceinfos.isNotEmpty) { + // 循环读取每个设备的hex数据 + for (var deviceInfo in deviceinfos) { + String? hexData = deviceInfo["hex"]; + if (hexData != null && hexData.length >= 28) { + // 确保hex数据长度足够(14字节 = 28个字符) + // 读取9-14字节的MAC地址 + String macFromHex = extractMacFromHex(hexData, device.address); + if (macFromHex.isNotEmpty) { + String code = ""; + // 找到匹配的设备,提取授权码 + if (Platform.isIOS) { + // iOS设备,提取13-22字节的授权码 + code = extractAndReverseBytes(hexData, 13, 22); + print('找到匹配设备,获取到 code: $code'); + if (code != "") { + deviceCode.value = code; + return 1; + } + } else if (Platform.isAndroid) { + // Android设备,提取15-24字节的授权码 + code = extractAndReverseBytes(hexData, 15, 24); + } + print('找到匹配设备,获取到 code: $code'); + if (code != "") { + deviceCode.value = code; + return 1; + } + } + } + } } 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 != "") { - deviceCode.value = code; - return 1; - } else { - return 0; - } - } return 0; - // 调用BLE管理器的自动绑定方法 } else { return 0; } } + // 新增方法:从hex数据中提取MAC地址并与当前设备MAC对比 + String extractMacFromHex(String hexData, String deviceMac) { + try { + // 将hex字符串转换为字节数组 + List bytes = []; + for (int i = 0; i < hexData.length; i += 2) { + bytes.add(int.parse(hexData.substring(i, i + 2), radix: 16)); + } + + // 读取9-14字节(索引8-13)的MAC地址 + if (bytes.length < 14) { + return ""; + } + + List macBytes = []; + if (Platform.isIOS) { + for (int i = 7; i <= 12; i++) { + // 每个字节异或0x5A + int decodedByte = bytes[i] ^ 0x5A; + macBytes.add(decodedByte); + } + } else if (Platform.isAndroid) { + for (int i = 9; i <= 14; i++) { + // 每个字节异或0x5A + int decodedByte = bytes[i] ^ 0x5A; + macBytes.add(decodedByte); + } + } + + // 将MAC字节转换为MAC地址字符串格式 + String extractedMac = macBytes + .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) + .join(':'); + + // 格式化当前设备MAC地址(确保格式一致) + String formattedDeviceMac = deviceMac.replaceAll(':', '').toUpperCase(); + String formattedExtractedMac = + extractedMac.replaceAll(':', '').toUpperCase(); + + print('设备MAC: $deviceMac, 提取的MAC: $extractedMac'); + + // 对比MAC地址 + if (formattedDeviceMac == formattedExtractedMac) { + print('MAC地址匹配成功!'); + return extractedMac; + } else { + print('MAC地址不匹配'); + return ""; + } + } catch (e) { + print('提取MAC地址时出错: $e'); + return ""; + } + } + //确认绑定设备 void confirmBindDevice() async { final response = await Api.bindearphone({ "code": deviceCode.value, "earphonname": currentDevice?.name, - "earphonemac": currentDevice?.address, + "earphonemac": currentDevice?.address, // 使用 address 替代 deviceId }); Logger.i(_tag, '手动授权结果 ${response}'); if (response != null) { Logger.i(_tag, '绑定设备成功'); - User.instance.earphonemac = currentDevice?.address ?? ''; + User.instance.earphonemac = currentDevice?.address ?? ''; // 使用 address User.instance.earphonename = currentDevice?.name ?? ''; User.instance.earphonelicense = deviceCode.value; _transition(PairingState.verifying); @@ -660,11 +750,11 @@ class PairingController extends GetxController { final response = await Api.bindauthcode({ "code": codeInputController.text.trim(), "earphonname": currentDevice?.name, - "earphonemac": currentDevice?.address, + "earphonemac": currentDevice?.address, // 使用 address 替代 deviceId }); Logger.i(_tag, '手动授权结果 ${response}'); if (response != null) { - User.instance.earphonemac = currentDevice?.address ?? ''; + User.instance.earphonemac = currentDevice?.address ?? ''; // 使用 address User.instance.earphonename = currentDevice?.name ?? ''; User.instance.earphoneauthcode = codeInputController.text.trim(); _transition(PairingState.verifying); diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift index ae25e7e3b..5e78731c1 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift @@ -165,31 +165,32 @@ public class BleService: NSObject { } /// 开始扫描BLE设备 - public func startScan(timeout: TimeInterval = 30.0) { + public func startScan(timeout: TimeInterval = 30.0) -> Bool { if centralManager == nil { initializeCentralManager() } guard let manager = centralManager, manager.state == .poweredOn else { os_log("❌ 蓝牙未就绪,无法开始扫描", log: logger, type: .error) - return + return false } if isScanning { - stopScan() + return true } // 清空之前的扫描结果 discoveredDevices.removeAll() + deviceAdvertisementData.removeAll() isScanning = true - let serviceUUIDs = [BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID] - manager.scanForPeripherals(withServices: serviceUUIDs, options: [ - CBCentralManagerScanOptionAllowDuplicatesKey: false + // 移除服务UUID过滤,扫描所有设备 + manager.scanForPeripherals(withServices: nil, options: [ + CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据 ]) - os_log("🔍 开始扫描BLE设备,超时时间: %.1f秒", log: logger, type: .info, timeout) + os_log("🔍 开始扫描所有BLE设备(无过滤),超时时间: %.1f秒", log: logger, type: .info, timeout) // 设置扫描超时 scanTimer?.invalidate() @@ -197,6 +198,7 @@ public class BleService: NSObject { self?.stopScan() os_log("⏰ 扫描超时,自动停止", log: self?.logger ?? OSLog.default, type: .info) } + return true } /// 停止扫描 @@ -206,7 +208,20 @@ public class BleService: NSObject { isScanning = false scanTimer?.invalidate() scanTimer = nil - os_log("⏹️ 停止BLE扫描", log: logger, type: .info) + +// let deviceCount = discoveredDevices.count +// os_log("⏹️ 停止BLE扫描,共发现 %d 个设备", log: logger, type: .info, deviceCount) +// +// // 打印所有发现的设备摘要 +// if deviceCount > 0 { +// os_log("📋 扫描结果摘要:", log: logger, type: .info) +// for (index, deviceInfo) in discoveredDevices.values.enumerated() { +// if let name = deviceInfo["name"] as? String, +// let rssi = deviceInfo["rssi"] as? Int { +// os_log("📋 %d. %{public}@ (RSSI: %d)", log: logger, type: .info, index + 1, name, rssi) +// } +// } +// } } } @@ -331,6 +346,75 @@ public class BleService: NSObject { return Array(discoveredDevices.values) } + /// 根据设备名称获取设备列表 + public func getDeviceAdvertisementData(deviceName: String) -> [[String: Any]] { + var matchingDevices: [[String: Any]] = [] + + // 遍历所有已发现的设备,查找匹配的设备名 + for (deviceId, deviceInfo) in discoveredDevices { + if let name = deviceInfo["name"] as? String, name == deviceName { + // 获取对应的广播数据 + var deviceData = deviceInfo + if let advData = deviceAdvertisementData[deviceId] { + // 合并设备信息和广播数据 + deviceData.merge(advData) { (current, _) in current } + } + matchingDevices.append(deviceData) + } + } + + os_log("根据设备名 '%{public}@' 找到 %d 个匹配设备", log: logger, type: .debug, deviceName, matchingDevices.count) + return matchingDevices + } + + /// 获取设备的制造商数据(hex格式) + public func getDeviceManufacturerDataHex(deviceId: String) -> String? { + guard let advData = deviceAdvertisementData[deviceId], + let manufacturerData = advData["manufacturerDataRaw"] as? Data else { + return nil + } + return manufacturerData.map { String(format: "%02x", $0) }.joined(separator: " ") + } + + /// 获取所有设备的广播数据摘要 + public func getAllDevicesAdvertisementData() -> [String: [String: Any]] { + return deviceAdvertisementData + } + + /// 获取设备信息 + public func getDeviceInfo(deviceId: String) -> [String: Any]? { + // 直接从缓存获取,与 Android 端逻辑保持一致 + if let cachedInfo = discoveredDevices[deviceId] { + os_log("获取设备信息: %{public}@", log: logger, type: .debug, deviceId) + return cachedInfo + } + + os_log("未找到设备信息: %{public}@", log: logger, type: .error, deviceId) + return nil + } + + /// 清除过期的设备缓存(超过maxCacheTime的设备) + public func clearExpiredDevices() { + let currentTime = Date().timeIntervalSince1970 + let expiredDeviceIds = deviceAdvertisementData.compactMap { (deviceId, advData) -> String? in + if let timestamp = advData["timestamp"] as? TimeInterval, + currentTime - timestamp > maxCacheTime { + return deviceId + } + return nil + } + + for deviceId in expiredDeviceIds { + discoveredDevices.removeValue(forKey: deviceId) + deviceAdvertisementData.removeValue(forKey: deviceId) + os_log("🗑️ 清除过期设备缓存: %{public}@", log: logger, type: .debug, deviceId) + } + + if !expiredDeviceIds.isEmpty { + os_log("🗑️ 已清除%d个过期设备缓存", log: logger, type: .info, expiredDeviceIds.count) + } + } + // MARK: - 回调通知方法 /// 通知所有回调扫描结果 @@ -1053,76 +1137,118 @@ extension BleService: CBCentralManagerDelegate { } } - // 原有方法 public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { let deviceId = peripheral.identifier.uuidString let deviceName = peripheral.name ?? "Unknown" - // 构建设备基本信息 + // 简化的设备信息构建 - 参考 Android 端的简洁性 + let deviceInfo = buildDeviceInfo(peripheral: peripheral, advertisementData: advertisementData, rssi: RSSI) + + // 检查是否为新设备或信息有重要变化 + var shouldNotify = false + + if let existingDevice = discoveredDevices[deviceId] { + // 设备已存在,检查是否有重要变化 + let oldRssi = existingDevice["rssi"] as? Int ?? 0 + let newRssi = RSSI.intValue + + // 只有当RSSI变化超过阈值时才上报(避免频繁更新) + if abs(newRssi - oldRssi) > 10 { + shouldNotify = true + os_log("📱 设备RSSI变化较大 - 名称: %{public}@, UUID: %{public}@, RSSI: %d → %d", log: logger, type: .debug, deviceName, deviceId, oldRssi, newRssi) + } + } else { + // 新设备,需要上报 + shouldNotify = true + os_log("📱 发现新设备 - 名称: %{public}@, UUID: %{public}@", log: logger, type: .info, deviceName, deviceId) + + // 打印 hex 数据 - 直接从 deviceInfo 获取 + if let hex = deviceInfo["hex"] as? String { + os_log("📡 设备 hex 数据: %{public}@", log: logger, type: .info, hex) + } + } + + // 更新缓存(无论是否上报都要更新) + discoveredDevices[deviceId] = deviceInfo + + // 只有在需要时才上报 + if shouldNotify { + notifyScanResult(devices: [deviceInfo]) + } + } + + // 新增:统一的设备信息构建方法 + private func buildDeviceInfo(peripheral: CBPeripheral, advertisementData: [String: Any], rssi: NSNumber) -> [String: Any] { + let deviceId = peripheral.identifier.uuidString + let deviceName = peripheral.name ?? "Unknown" + + // 基本设备信息 - 与 Android 端格式对齐 var deviceInfo: [String: Any] = [ - "name": deviceName, "id": deviceId, - "rssi": RSSI.intValue, + "name": deviceName, + "rssi": rssi.intValue, "discoveredAt": Date().timeIntervalSince1970 ] - // 详细的广播数据记录 - var advData: [String: Any] = [:] - - // 制造商数据 - if let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data { - deviceInfo["manufacturerData"] = manufacturerData - advData["manufacturerData"] = manufacturerData.map { String(format: "%02x", $0) }.joined(separator: " ") - advData["manufacturerDataRaw"] = manufacturerData - } - - // 服务UUID列表 + // 服务 UUIDs - 与 Android 端保持一致的字段名 if let serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] { - let serviceUUIDStrings = serviceUUIDs.map { $0.uuidString } - deviceInfo["serviceUUIDs"] = serviceUUIDStrings - advData["serviceUUIDs"] = serviceUUIDStrings + let uuids = serviceUUIDs.map { $0.uuidString } + deviceInfo["uuids"] = uuids // 使用与 Android 端一致的字段名 } - // 本地名称 - if let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String { - advData["localName"] = localName + // 只存储 hex 数据 - 简化存储 + if let rawData = extractRawAdvertisementData(from: advertisementData) { + deviceInfo["hex"] = rawData // 直接存储 hex 数据,不使用 advertisementData 包装 } - // 发射功率 - if let txPowerLevel = advertisementData[CBAdvertisementDataTxPowerLevelKey] as? NSNumber { - advData["txPowerLevel"] = txPowerLevel.intValue + return deviceInfo + } + + // 提取原始广播数据的辅助方法 + private func extractRawAdvertisementData(from advertisementData: [String: Any]) -> String? { + // 尝试从各种数据源构建原始数据的十六进制表示 + var allData = Data() + + if let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data { + allData.append(manufacturerData) } - // 服务数据 if let serviceData = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] { - var serviceDataDict: [String: String] = [:] - for (uuid, data) in serviceData { - serviceDataDict[uuid.uuidString] = data.map { String(format: "%02x", $0) }.joined(separator: " ") + for (_, data) in serviceData { + allData.append(data) } - advData["serviceData"] = serviceDataDict } - // 可连接性 - if let isConnectable = advertisementData[CBAdvertisementDataIsConnectable] as? NSNumber { - advData["isConnectable"] = isConnectable.boolValue + return allData.isEmpty ? nil : allData.map { String(format: "%02X", $0) }.joined() + } + + // 数据清理方法 + private func sanitizeData(_ dict: [String: Any]) -> [String: Any] { + var sanitized: [String: Any] = [:] + for (key, value) in dict { + if value is Data { + // 跳过 Data 对象 + continue + } else if let nestedDict = value as? [String: Any] { + sanitized[key] = sanitizeData(nestedDict) + } else if let array = value as? [Any] { + var filteredArray: [Any] = [] + for item in array { + if item is Data { + // 跳过 Data 对象 + continue + } else if let nestedDict = item as? [String: Any] { + filteredArray.append(sanitizeData(nestedDict)) + } else { + filteredArray.append(item) + } + } + sanitized[key] = filteredArray + } else { + sanitized[key] = value + } } - - // 完整的广播数据 - advData["rssi"] = RSSI.intValue - advData["timestamp"] = Date().timeIntervalSince1970 - - // 缓存设备信息和广播数据 - discoveredDevices[deviceId] = deviceInfo - deviceAdvertisementData[deviceId] = advData - - // 添加广播数据到设备信息中 - deviceInfo["advertisementData"] = advData - - os_log("📡 发现设备: %{public}@ (ID: %{public}@), RSSI: %d", log: logger, type: .info, deviceName, deviceId, RSSI.intValue) - os_log("📡 广播数据: %{public}@", log: logger, type: .debug, String(describing: advData)) - - // 报告给回调 - notifyScanResult(devices: [deviceInfo]) + return sanitized } public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift index 4d94982ec..c602bb7fa 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift @@ -118,6 +118,12 @@ public class SwiftBleServicePlugin: NSObject, FlutterPlugin { os_log("⏹️ 停止BLE扫描", log: logger, type: .info) BleService.shared.stopScan() result(true) + case "getDeviceList": + let arguments = call.arguments as? [String: Any] + let deviceName = (arguments?["deviceName"] as? String) ?? "" + os_log("🔍 查询设备信息,deviceName: %s", log: logger, type: .info, deviceName) + let info = BleService.shared.getDeviceAdvertisementData(deviceName: deviceName) + result(info) case "connectToDevice": let arguments = call.arguments as? [String: Any] @@ -127,14 +133,12 @@ public class SwiftBleServicePlugin: NSObject, FlutterPlugin { details: nil)) return } - os_log("🔗 连接到设备: %@", log: logger, type: .info, deviceId) let success = BleService.shared.connectToDevice(uuid: deviceId) result(success) - - case "getDiscoveredDevices": - let devices = BleService.shared.getDiscoveredDevices() - result(devices) + case "clearExpiredDevices": + BleService.shared.clearExpiredDevices() + result(true) case "requestBluetoothPermission": // 移除这个方法调用,让iOS系统自然处理权限 diff --git a/local_plugins/ble_service/lib/ble_service.dart b/local_plugins/ble_service/lib/ble_service.dart index 844c9c594..5a384bfc1 100644 --- a/local_plugins/ble_service/lib/ble_service.dart +++ b/local_plugins/ble_service/lib/ble_service.dart @@ -293,16 +293,19 @@ class BleService { } } - /// 断开连接 - Future?> getDeviceInfo(String address) async { + /// 获取设备信息 + Future?> getDeviceInfo(String deviceName) async { try { final result = await _methodChannel - .invokeMethod('getDeviceInfo', {'address': address}); + .invokeMethod('getDeviceInfo', {'deviceName': deviceName}); print('获取设备信息!: $result'); if (result != null) { return { 'name': result['name'] ?? "未知", 'address': result['address'] ?? "", + 'id': result['id'] ?? + result['address'] ?? + "", // iOS 返回 UUID,Android 返回 address 'hex': result['hex'] ?? "", }; } else { @@ -314,6 +317,32 @@ class BleService { } } + /// 获取设备列表(通过设备名) + Future>?> getDeviceList(String deviceName) async { + try { + final result = await _methodChannel + .invokeMethod('getDeviceList', {'deviceName': deviceName}); + print('获取设备列表!: $result'); + if (result != null) { + return result.map>((device) { + return { + 'name': device['name'] ?? "未知", + 'address': device['address'] ?? "", + 'id': device['id'] ?? + device['address'] ?? + "", // iOS 返回 UUID,Android 返回 address + 'hex': device['hex'] ?? "", + }; + }).toList(); + } else { + return null; + } + } catch (e) { + print('获取设备列表失败!: $e'); + return null; + } + } + /// 注册BLE后台扫描 /// /// 注册后,即使应用被杀死,系统也会在检测到设备广播时唤醒应用 @@ -439,7 +468,8 @@ class BleService { /// 请求蓝牙权限(仅iOS) Future requestBluetoothPermission() async { try { - final result = await _methodChannel.invokeMethod('requestBluetoothPermission'); + final result = + await _methodChannel.invokeMethod('requestBluetoothPermission'); return result ?? false; } catch (e) { print('请求蓝牙权限失败: $e');