import Foundation import ExternalAccessory import CoreBluetooth /// 蓝牙事件类型 enum BluetoothEventType { case stateChanged case deviceConnected case deviceDisconnected } /// 蓝牙状态枚举 enum BluetoothState: String { case unknown = "unknown" case off = "off" case on = "on" case turningOn = "turningOn" case turningOff = "turningOff" } /// 经典蓝牙助手类,负责iOS上的蓝牙设备管理 class ClassicBluetoothHelper: NSObject { private let TAG = "ClassicBluetoothHelper" // 状态监控相关 private var isMonitoring = false private var stateCallback: ((BluetoothEventType, [String: Any]) -> Void)? // 用于监控蓝牙系统状态 private var centralManager: CBCentralManager? // 通知观察者 private var accessoryConnectionObserver: NSObjectProtocol? private var accessoryDisconnectionObserver: NSObjectProtocol? override init() { super.init() centralManager = CBCentralManager(delegate: nil, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey: false]) } deinit { stopBluetoothStateMonitoring() } /// 检查蓝牙是否启用 func isBluetoothEnabled() -> Bool { guard let centralManager = centralManager else { return false } return centralManager.state == .poweredOn } /// 获取已连接的蓝牙设备 /// - Parameter completion: 完成回调 func getConnectedDevices(completion: @escaping ([[String: String]], Error?) -> Void) { // 获取所有已连接的外部配件 let accessoryManager = EAAccessoryManager.shared() let connectedAccessories = accessoryManager.connectedAccessories // 将配件转换为设备信息数组 let devices = connectedAccessories.map { accessory -> [String: String] in return [ "name": accessory.name, "address": accessory.serialNumber // iOS使用序列号作为唯一标识 ] } // 返回结果 completion(devices, nil) } /// 开始监听蓝牙状态变化 /// - Parameter callback: 状态变化回调 func startBluetoothStateMonitoring(callback: @escaping (BluetoothEventType, [String: Any]) -> Void) { self.stateCallback = callback if !isMonitoring { isMonitoring = true // 设置蓝牙中央管理器代理 centralManager?.delegate = self // 注册蓝牙配件连接/断开通知 let notificationCenter = NotificationCenter.default // 观察配件连接 accessoryConnectionObserver = notificationCenter.addObserver( forName: NSNotification.Name.EAAccessoryDidConnect, object: nil, queue: nil ) { [weak self] notification in guard let self = self, let accessory = notification.userInfo?[EAAccessoryKey] as? EAAccessory else { return } let device: [String: String] = [ "name": accessory.name, "address": accessory.serialNumber ] self.stateCallback?(.deviceConnected, ["device": device]) } // 观察配件断开 accessoryDisconnectionObserver = notificationCenter.addObserver( forName: NSNotification.Name.EAAccessoryDidDisconnect, object: nil, queue: nil ) { [weak self] notification in guard let self = self, let accessory = notification.userInfo?[EAAccessoryKey] as? EAAccessory else { return } let device: [String: String] = [ "name": accessory.name, "address": accessory.serialNumber ] self.stateCallback?(.deviceDisconnected, ["device": device]) } // 开始监视配件变化 EAAccessoryManager.shared().registerForLocalNotifications() } } /// 停止监听蓝牙状态变化 func stopBluetoothStateMonitoring() { if isMonitoring { isMonitoring = false // 移除蓝牙中央管理器代理 centralManager?.delegate = nil // 注销配件通知观察者 if let observer = accessoryConnectionObserver { NotificationCenter.default.removeObserver(observer) accessoryConnectionObserver = nil } if let observer = accessoryDisconnectionObserver { NotificationCenter.default.removeObserver(observer) accessoryDisconnectionObserver = nil } // 停止监视配件变化 EAAccessoryManager.shared().unregisterForLocalNotifications() } // 清除回调 stateCallback = nil } /// 报告当前蓝牙状态 func reportCurrentBluetoothState() { guard let centralManager = centralManager else { return } let state: BluetoothState switch centralManager.state { case .poweredOn: state = .on case .poweredOff: state = .off case .resetting: state = .turningOff // 最接近的近似值 case .unauthorized, .unsupported: state = .off // 功能上等同于关闭 default: state = .unknown } stateCallback?(.stateChanged, ["state": state.rawValue]) } } // MARK: - CBCentralManagerDelegate extension ClassicBluetoothHelper: CBCentralManagerDelegate { func centralManagerDidUpdateState(_ central: CBCentralManager) { let state: BluetoothState switch central.state { case .poweredOn: state = .on case .poweredOff: state = .off case .resetting: state = .turningOff case .unauthorized, .unsupported: state = .off default: state = .unknown } stateCallback?(.stateChanged, ["state": state.rawValue]) } }