diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index 5d1af6ca3..25867c571 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -532,7 +532,7 @@ class BleManager extends GetxService { try { // 从.env文件直接读取环境变量 var serverurl = dotenv.env['SERVER_URL'] ?? ''; - if (Get.deviceLocale?.countryCode != 'CN') { + if (Get.locale?.countryCode != 'CN') { serverurl = dotenv.env['HW_SERVER_URL'] ?? ''; } @@ -860,9 +860,9 @@ class BleManager extends GetxService { } } - Future>?> getDeviceList(String devicename) async { + Future>?> getDeviceList(String deviceName) async { try { - final result = _bleService.getDeviceList(devicename); + 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 feddfb18e..5cc66c30b 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -844,9 +844,11 @@ class PairingController extends GetxController with WidgetsBindingObserver { license: ''), ); if (existingDevice.id != -1) { + _bleManager.stopScan(); // 已经绑定 return 10; } else { + _bleManager.stopScan(); return 1; } } @@ -874,9 +876,11 @@ class PairingController extends GetxController with WidgetsBindingObserver { license: ''), ); if (existingDevice.id != -1) { + _bleManager.stopScan(); // 已经绑定 return 10; } else { + _bleManager.stopScan(); return 1; } } @@ -889,6 +893,7 @@ class PairingController extends GetxController with WidgetsBindingObserver { } await Future.delayed(Duration(seconds: 1)); } + _bleManager.stopScan(); if (product != null && product.devicetype == 2) { //ble设备 必须要扫描到结果 return 0; diff --git a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift index e070c9db3..06452fe1f 100644 --- a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift +++ b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift @@ -19,6 +19,7 @@ extension Notification.Name { static let navigationdEvent = Notification.Name("navigationdEvent") //导航事件 static let locationstartEvent = Notification.Name("locationstartEvent") //启动定位 static let updatelocationEvent = Notification.Name("updatelocationEvent") //更新位置事件 + static let exitnavigationdEvent = Notification.Name("exitnavigationdEvent") //退出导航事件 } class AgentServiceImpl: NSObject { private let TAG = "AgentServiceImpl" diff --git a/local_plugins/amap_service/ios/Classes/AmapViewController.swift b/local_plugins/amap_service/ios/Classes/AmapViewController.swift index 49092abc2..c6bda6a36 100644 --- a/local_plugins/amap_service/ios/Classes/AmapViewController.swift +++ b/local_plugins/amap_service/ios/Classes/AmapViewController.swift @@ -92,38 +92,39 @@ class AmapViewController: UIViewController { } private func setupAMapComponents() { + self.addNSNotification(); // 1. 初始化 DriveView(必须在主线程) - print("导航------------------ setupAMapComponents_1") +// print("导航------------------ setupAMapComponents_1") DispatchQueue.main.async { - print("导航------------------ setupAMapComponents_2") +// print("导航------------------ setupAMapComponents_2") self.driveView = AMapNaviDriveView(frame: self.view.bounds) - print("导航------------------ setupAMapComponents_3") +// print("导航------------------ setupAMapComponents_3") self.driveView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - print("导航------------------ setupAMapComponents_4") +// print("导航------------------ setupAMapComponents_4") self.driveView.delegate = self - print("导航------------------ setupAMapComponents_5") +// print("导航------------------ setupAMapComponents_5") self.view.addSubview(self.driveView) - print("导航------------------ setupAMapComponents_6") +// print("导航------------------ setupAMapComponents_6") // 2. 初始化 DriveManager self.driveManager = AMapNaviDriveManager.sharedInstance() - print("导航------------------ setupAMapComponents_7") +// print("导航------------------ setupAMapComponents_7") self.driveManager.delegate = self - print("导航------------------ setupAMapComponents_8") +// print("导航------------------ setupAMapComponents_8") self.driveManager.allowsBackgroundLocationUpdates = true - print("导航------------------ setupAMapComponents_9") +// print("导航------------------ setupAMapComponents_9") // 3. 确保对象非空再关联 if let manager = self.driveManager, let view = self.driveView { - print("导航------------------ setupAMapComponents_10") +// print("导航------------------ setupAMapComponents_10") manager.addDataRepresentative(view) - print("导航------------------ setupAMapComponents_11") +// print("导航------------------ setupAMapComponents_11") self.startNavigation() - print("导航------------------ setupAMapComponents_12") +// print("导航------------------ setupAMapComponents_12") } else { print("Error: driveManager or driveView is nil") } - print("导航------------------ setupAMapComponents_13") +// print("导航------------------ setupAMapComponents_13") } } @@ -144,26 +145,38 @@ class AmapViewController: UIViewController { } @objc private func exitNavigation() { - print("导航------------------ 退出导航,清理资源") - // 停止导航 - driveManager.stopNavi() - driveManager.removeDataRepresentative(driveView) - driveManager.delegate = nil - - // 移除导航视图 - driveView.delegate = nil - driveView.removeFromSuperview() - driveView = nil - - // 销毁导航管理器 - driveManager = nil - - // 关闭当前页面,视情况而定 - // 如果你用的是导航控制器,可以pop - navigationController?.popViewController(animated: true) - // 或者如果是present出来的,dismiss - // dismiss(animated: true, completion: nil) - } + print("导航------------------ 退出导航,清理资源") + // 停止导航 + driveManager.stopNavi() + driveManager.removeDataRepresentative(driveView) + driveManager.delegate = nil + + // 移除导航视图 + driveView.delegate = nil + driveView.removeFromSuperview() + driveView = nil + + // 销毁导航管理器 + driveManager = nil + + // 关闭当前页面 - 修复:使用正确的退出方式 + if let navigationController = navigationController { + // 如果是在导航控制器中,使用 pop + navigationController.popViewController(animated: true) + } else { + // 如果是 present 出来的,使用 dismiss + dismiss(animated: true, completion: nil) + } + } + private func addNSNotification(){ + NotificationCenter.default.addObserver( + forName: NSNotification.Name("ExitNavigation"), + object: nil, + queue: .main + ) { _ in + self.exitNavigation() + } + } } // MARK: - 代理方法 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 cb8d6d962..dc8389a0e 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 @@ -89,6 +89,7 @@ object BleService { // 扫描相关 private lateinit var scanHandler: Handler private val scanResults = ArrayList() + @Volatile private var isScanning = false // 是否是ota模式 @@ -307,27 +308,32 @@ object BleService { Log.i(TAG, "开始主动扫描BLE设备...") scanResults.clear() // Log.i(TAG, "liwei---------startScan 5") -// val filter = ScanFilter.Builder() -// // .setServiceUuid(ParcelUuid(BleConst.PRIMARY_SERVICE_UUID)) + val filter = ScanFilter.Builder() + // .setServiceUuid(ParcelUuid(BleConst.PRIMARY_SERVICE_UUID)) // .setManufacturerData(0xEFAB, byteArrayOf(0xA0.toByte(), 0x01)) -// .build() -// Log.i(TAG, "liwei---------startScan 6") -// val settings = ScanSettings.Builder() -// .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) -// // .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH) -// .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH) // 使用ALL_MATCHES获取所有结果 -// .setReportDelay(0) // 立即报告结果 -// .build() -// val filter = ScanFilter.Builder() -// // 建议用 Service UUID 或 Device Name 替代 Manufacturer Data -// // .setServiceUuid(ParcelUuid(BleConst.PRIMARY_SERVICE_UUID)) -//// .setDeviceName(deviceName) // 更通用、更安全 -// .build() - val filters = uuids.map { uuidStr -> - ScanFilter.Builder() - .setServiceUuid(ParcelUuid(UUID.fromString(uuidStr))) - .build() - } + .build() +// val filters = uuids.mapNotNull { uuidStr -> +// try { +// // 清理UUID字符串,移除非十六进制字符 +// val cleanUuidStr = uuidStr.replace("[^0-9A-Fa-f]".toRegex(), "") +// +// // 验证清理后的字符串长度(应该是4位十六进制字符) +// if (cleanUuidStr.length != 4) { +// Log.w(TAG, "无效的UUID格式: $uuidStr,清理后: $cleanUuidStr,长度: ${cleanUuidStr.length}") +// return@mapNotNull null +// } +// +// val fullUuid = "0000$cleanUuidStr-0000-1000-8000-00805f9b34fb" +// Log.d(TAG, "扫描uuid: $fullUuid") +// +// ScanFilter.Builder() +// .setServiceUuid(ParcelUuid(UUID.fromString(fullUuid))) +// .build() +// } catch (e: IllegalArgumentException) { +// Log.e(TAG, "构造UUID失败: $uuidStr", e) +// null +// } +// } val settings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) // 推荐:不会触发权限问题 @@ -335,7 +341,7 @@ object BleService { .build() // Log.i(TAG, "liwei---------startScan 7") try { - scanner.startScan(filters, settings, scanCallback) + scanner.startScan(listOf(filter), settings, scanCallback) isScanning = true // Log.i(TAG, "liwei---------startScan 8") // 设置扫描超时 @@ -348,7 +354,7 @@ object BleService { } catch (e: Exception) { Log.e(TAG, "启动扫描失败: ${e.message}", e) // Log.i(TAG, "liwei---------startScan 10") -// isScanning = false + isScanning = false return false } } @@ -468,10 +474,10 @@ object BleService { val serviceUuids = scanRecord?.serviceUuids?.joinToString(", ") { it.uuid.toString() } ?: "无" -// Log.d( -// TAG, "liwei--------- 扫描到设备: 名称=${device.name ?: "未知"}, 地址=${device.address}, " + -// "RSSI=${result.rssi}, 服务UUID=[$serviceUuids]" - // ) + Log.d( + TAG, "liwei--------- 扫描到设备: 名称=${device.name ?: "未知"}, 地址=${device.address}, " + + "RSSI=${result.rssi}, 服务UUID=[$serviceUuids]" + ) val info = mutableMapOf( "name" to (device.name ?: "未知"), "address" to device.address 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 de20dd940..12a29477d 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 @@ -302,8 +302,8 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } } "startScan" -> { - val devicename = call.argument("devicename")?:"" - val connected = BleService.startScan(devicename) + val uuids = call.argument>("uuids")?:emptyList() + val connected = BleService.startScan(uuids) result.success(connected) } "getDeviceInfo" -> { diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt index adacdafd9..af83a46d0 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt @@ -164,7 +164,7 @@ class SystemFunctionHandler(private val context: Context? = null) { handler = OpenRecorderHandler(context) ) - // 注册退出交互函数 + // 退出导航 client.registerLocalFunction( name = "exit_navigation", description = "结束当前导航服务", diff --git a/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift b/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift index 6f2bcf72d..fbe0419d1 100644 --- a/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift +++ b/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift @@ -8,6 +8,7 @@ import user_portrait // 添加这行 import MediaPlayer import AVFoundation +import UserNotifications // 在文件顶部添加通知名称定义 extension Notification.Name { @@ -64,9 +65,11 @@ public class SystemFunctionHandler: NSObject { do { // 注册退出交互函数 registerExitInteractionFunction(client: client) + // 注册退出导航模式 + registerExitNavigationFunction(client: client) // 注册翻译模式函数 - registerTranslationModeFunction(client: client) +// registerTranslationModeFunction(client: client) // 注册发送短信函数 registerSendTextMessageFunction(client: client) @@ -119,7 +122,22 @@ public class SystemFunctionHandler: NSObject { handler: handler ) } - + /// 注册退出交互函数 + private func registerExitNavigationFunction(client: MCPClient) { + let parameters: [String: Any] = [ + "type": "object", + "properties": [:], + "required": [] + ] + + let handler = ExitNavigationHandler() + _ = client.registerLocalFunction( + name: "exit_navigation", + description: "结束当前导航", + parameters: parameters, + handler: handler + ) + } /// 注册翻译模式函数 private func registerTranslationModeFunction(client: MCPClient) { let parameters: [String: Any] = [ @@ -558,7 +576,13 @@ private class ExitInteractionHandler: FunctionHandler { return "{\"result\": \"已结束当前交互\"}" } } - +/// 退出交互处理器 +private class ExitNavigationHandler: FunctionHandler { + func handle(arguments: [String: Any]) async throws -> String { + NotificationCenter.default.post(name: NSNotification.Name("ExitNavigation"), object: nil) + return "{\"result\": \"已结束当前导航\"}" + } +} /// 翻译模式处理器 private class TranslationModeHandler: FunctionHandler { func handle(arguments: [String: Any]) async throws -> String { @@ -670,12 +694,12 @@ private class MakePhoneCallHandler: FunctionHandler { /// 设置提醒处理器 private class SetReminderHandler: FunctionHandler { - private let eventStore: EKEventStore? + private var eventStore: EKEventStore? = EKEventStore() init(eventStore: EKEventStore?) { self.eventStore = eventStore } - + func handle(arguments: [String: Any]) async throws -> String { guard let title = arguments["title"] as? String, let timeString = arguments["time"] as? String else { @@ -683,99 +707,113 @@ private class SetReminderHandler: FunctionHandler { } let content = arguments["content"] as? String ?? "" - let result = await setReminder(title: title, content: content, time: timeString) + let result = await setAlarmReminder(title: title, content: content, time: timeString) return "{\"result\": \"\(result.message)\"}" } - - private func setReminder(title: String, content: String, time: String) async -> Result { - guard let eventStore = eventStore else { - return Result(success: false, message: "事件存储未初始化") + + // 设置闹钟级提醒(主方法) + func setAlarmReminder(title: String, content: String, time: String) async -> Result { + // 1. 请求日历权限 + let calendarStatus = await EKEventStore.authorizationStatus(for: .reminder) + guard calendarStatus == .authorized else { + let message = calendarStatus == .denied + ? "日历权限已拒绝,请前往「设置 → 隐私与安全 → 日历」开启" + : "日历权限不足" + return Result(success: false, message: message) } - // 请求日历权限 - let status = await requestCalendarAccess() - print("[SetReminder] 权限检查结果: \(status.rawValue) - \(statusDescription(status))") - - switch status { - case .authorized: - // 权限已授权,继续执行 - break - case .denied: - return Result(success: false, message: "日历权限被拒绝,请前往 设置 > 隐私与安全 > 日历 中开启权限") - case .restricted: - return Result(success: false, message: "日历权限受限制,可能由于家长控制或企业策略限制") - case .notDetermined: - return Result(success: false, message: "日历权限未确定,请重试") - @unknown default: - return Result(success: false, message: "日历权限状态未知") + // 2. 请求关键通知权限(闹钟级提醒必需) + let notificationCenter = UNUserNotificationCenter.current() + do { + let granted = try await notificationCenter.requestAuthorization(options: [.alert, .sound, .criticalAlert]) + guard granted else { + return Result(success: false, message: "请在「设置 → 你的App → 通知」中开启关键通知权限") + } + } catch { + return Result(success: false, message: "通知权限请求失败:\(error.localizedDescription)") } - // 解析时间 + // 3. 解析并验证时间(必须在当前时间10秒后) let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm" - guard let date = formatter.date(from: time) else { + formatter.timeZone = TimeZone.current + guard let targetDate = formatter.date(from: time), targetDate.timeIntervalSinceNow > 10 else { return Result(success: false, message: "时间格式错误") } - // 创建提醒 + // 4. 创建日历提醒(作为备份) + let calendarResult = await createCalendarReminder(title: title, content: content, date: targetDate) + guard calendarResult.success else { + return calendarResult + } + + // 5. 创建关键通知(闹钟级效果核心) + return await createCriticalNotification(title: title, content: content, date: targetDate) + } + + // 创建日历提醒(备份用) + private func createCalendarReminder(title: String, content: String, date: Date) async -> Result { + guard let eventStore = eventStore else { + return Result(success: false, message: "日历服务不可用") + } + let reminder = EKReminder(eventStore: eventStore) reminder.title = title reminder.notes = content - reminder.calendar = eventStore.defaultCalendarForNewReminders() - let alarm = EKAlarm(absoluteDate: date) - reminder.addAlarm(alarm) + // 获取可用日历 + guard let targetCalendar = eventStore.defaultCalendarForNewReminders() + ?? eventStore.calendars(for: .reminder).first(where: { $0.allowsContentModifications }) else { + return Result(success: false, message: "无可用日历,请先在系统日历中创建日历") + } + reminder.calendar = targetCalendar + reminder.addAlarm(EKAlarm(absoluteDate: date)) + // 保存提醒 do { try eventStore.save(reminder, commit: true) - return Result(success: true, message: "提醒设置成功") + return Result(success: true, message: "日历提醒已创建") } catch { - return Result(success: false, message: "设置提醒失败:\(error.localizedDescription)") - } - } - - private func requestCalendarAccess() async -> EKAuthorizationStatus { - return await withCheckedContinuation { continuation in - // 首先检查当前权限状态 - let currentStatus = EKEventStore.authorizationStatus(for: .reminder) - print("[Calendar] 当前权限状态: \(currentStatus.rawValue) - \(statusDescription(currentStatus))") - - // 如果已经授权,直接返回 - if currentStatus == .authorized { - continuation.resume(returning: currentStatus) - return - } - - // 如果被拒绝,也直接返回(避免重复请求) - if currentStatus == .denied { - print("[Calendar] 权限已被拒绝,需要用户手动在设置中开启") - continuation.resume(returning: currentStatus) - return - } - - // 请求权限 - eventStore?.requestAccess(to: .reminder) { granted, error in - let finalStatus = EKEventStore.authorizationStatus(for: .reminder) - print("[Calendar] 权限请求完成 - granted: \(granted), error: \(error?.localizedDescription ?? "无")") - print("[Calendar] 最终权限状态: \(finalStatus.rawValue) - \(self.statusDescription(finalStatus))") - continuation.resume(returning: finalStatus) - } + return Result(success: false, message: "日历提醒保存失败:\(error.localizedDescription)") } } - // 添加状态描述辅助方法 - private func statusDescription(_ status: EKAuthorizationStatus) -> String { - switch status { - case .notDetermined: - return "未确定" - case .restricted: - return "受限制" - case .denied: - return "被拒绝" - case .authorized: - return "已授权" - @unknown default: - return "未知状态" + // 创建关键通知(实现闹钟级效果) + private func createCriticalNotification(title: String, content: String, date: Date) async -> Result { + let notificationContent = UNMutableNotificationContent() + notificationContent.title = title + notificationContent.body = content + notificationContent.badge = 1 + + // 关键配置:闹钟级声音(突破静音,最大音量) + notificationContent.sound = UNNotificationSound.criticalSoundNamed( + UNNotificationSoundName("default"), + withAudioVolume: 1.0 + ) + + // 关键配置:最高优先级(突破勿扰,全屏弹窗) + notificationContent.interruptionLevel = .critical + notificationContent.relevanceScore = 1.0 // 最高相关性分数 + + // 设置触发时间(精确到秒) + let components = Calendar.current.dateComponents( + [.year, .month, .day, .hour, .minute, .second], + from: date + ) + let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false) + + // 发送通知请求 + let request = UNNotificationRequest( + identifier: "Alarm_\(UUID().uuidString)", + content: notificationContent, + trigger: trigger + ) + + do { + try await UNUserNotificationCenter.current().add(request) + return Result(success: true, message: "闹钟级提醒已设置,到点将强制响铃") + } catch { + return Result(success: false, message: "通知创建失败:\(error.localizedDescription)") } } } diff --git a/local_plugins/classic_bluetooth/ios/Classes/ClassicBluetoothHelper.swift b/local_plugins/classic_bluetooth/ios/Classes/ClassicBluetoothHelper.swift index 9d0b31890..533482149 100644 --- a/local_plugins/classic_bluetooth/ios/Classes/ClassicBluetoothHelper.swift +++ b/local_plugins/classic_bluetooth/ios/Classes/ClassicBluetoothHelper.swift @@ -1,5 +1,6 @@ import Foundation import AVFoundation +import CoreBluetooth /// 蓝牙事件类型 enum BluetoothEventType { @@ -18,32 +19,49 @@ enum BluetoothState: String { } /// 简化的蓝牙助手类,专注于iOS上的蓝牙耳机检测 -class ClassicBluetoothHelper: NSObject { - // 状态监控相关 - private var isMonitoring = false +class ClassicBluetoothHelper: NSObject, CBCentralManagerDelegate { + private var centralManager: CBCentralManager? + private var bluetoothState: CBManagerState = .unknown + + // 添加缺少的属性声明 private var stateCallback: ((BluetoothEventType, [String: Any]) -> Void)? + private var isMonitoring: Bool = false // 音频路由变化观察者 private var routeChangeObserver: NSObjectProtocol? + override init() { + super.init() + centralManager = CBCentralManager(delegate: self, queue: nil) + } + deinit { stopBluetoothStateMonitoring() } - /// 检查蓝牙是否启用(通过检查是否有连接的蓝牙音频设备) - func isBluetoothEnabled() -> Bool { - // 检查是否有连接的蓝牙音频设备 - let hasBtDevices = !getConnectedAudioDevices().isEmpty + func centralManagerDidUpdateState(_ central: CBCentralManager) { + bluetoothState = central.state + print("lxm---蓝牙状态更新: \(bluetoothState.rawValue)") - // 如果有连接的蓝牙设备,则认为蓝牙是开启状态 - if hasBtDevices { - print("蓝牙状态检查: 已检测到蓝牙设备,蓝牙已开启") + // 向Flutter端报告蓝牙状态变化 + if isMonitoring { + let currentState = getBluetoothAvailability() + reportBluetoothState(currentState) + } + } + + func isBluetoothEnabled() -> Bool { + switch bluetoothState { + case .poweredOn: return true + case .poweredOff, .unsupported, .unauthorized, .resetting: + return false + case .unknown: + // 如果状态未知,回退到原来的音频设备检测方法 + return !getConnectedAudioDevices().isEmpty + @unknown default: + return false } - - // 如果没有连接设备,返回false (无法100%确定蓝牙是否打开,只能知道没有连接设备) - print("蓝牙状态检查: 未检测到蓝牙设备") - return false } /// 获取已连接的蓝牙耳机 @@ -206,19 +224,47 @@ class ClassicBluetoothHelper: NSObject { print("关闭音频会话失败: \(error.localizedDescription)") } } + + /// 获取蓝牙可用性状态(优化后的统一状态判断方法) + func getBluetoothAvailability() -> BluetoothState { + switch bluetoothState { + case .poweredOn: + return .on + case .poweredOff: + return .off + case .unauthorized: + return .unauthorized + case .unsupported: + return .unsupported + case .unknown, .resetting: + // 当CoreBluetooth状态未知时,回退到音频设备检测 + return getConnectedAudioDevices().isEmpty ? .unknown : .on + @unknown default: + return .unknown + } + } - /// 报告当前蓝牙状态 + /// 报告当前蓝牙状态(优化后使用统一的状态判断方法) func reportCurrentBluetoothState() { - // 检查当前是否有蓝牙设备连接 - let devices = getConnectedAudioDevices() + // 使用优化后的统一状态判断方法 + let currentState = getBluetoothAvailability() - if !devices.isEmpty { - print("蓝牙状态: 已检测到蓝牙设备,报告状态为开启") - reportBluetoothState(.on) - } else { - print("蓝牙状态: 未检测到蓝牙设备,报告状态为未知") - reportBluetoothState(.unknown) + // 根据状态输出相应的日志信息 + switch currentState { + case .on: + print("蓝牙状态: 蓝牙已开启") + case .off: + print("蓝牙状态: 蓝牙已关闭") + case .unauthorized: + print("蓝牙状态: 应用未授权使用蓝牙") + case .unsupported: + print("蓝牙状态: 设备不支持蓝牙") + case .unknown: + print("蓝牙状态: 蓝牙状态未知") } + + // 向Flutter端报告状态 + reportBluetoothState(currentState) } // 报告蓝牙状态变化