You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

963 lines
35 KiB

import Foundation
import CoreBluetooth
import os.log
/// BLE服务类 - 单例实现
actor BleService {
// MARK: - 单例实现
static let shared = BleService()
// MARK: - 常量
/// 用于状态恢复的唯一标识符
private let restoreIdentifier = "com.yunqiinnovation.ble_service.restore"
private init() {
// 初始化连接状态
connectionState = BleConst.STATE_DISCONNECTED
// 将通知处理移到非actor方法中
setupNotifications()
}
deinit {
// 移除通知观察者
for observer in notificationObservers {
NotificationCenter.default.removeObserver(observer)
}
}
// MARK: - 属性
/// 中央管理器
private var centralManager: CBCentralManager?
/// 当前连接的外设
private var peripheral: CBPeripheral?
/// 主服务特征
private var writeCharacteristic: CBCharacteristic?
private var notifyCharacteristic: CBCharacteristic?
private var audioCharacteristic: CBCharacteristic?
/// 连接状态
private(set) var connectionState: Int {
didSet {
if oldValue != connectionState {
Task { await notifyConnectionStateChanged(state: connectionState) }
}
}
}
/// 是否正在扫描
private(set) var isScanning = false
/// 扫描结果缓存
private var scanResults = [CBPeripheral: [String: Any]]()
/// 扫描超时任务
private var scanTimeoutTask: Task<Void, Never>?
/// 是否已初始化
private var isInitialized = false
/// 回调代理列表 - 使用actor保证线程安全
private var delegates = [BleDelegate]()
/// 日志
private let logger = OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService")
/// 通知观察者
private var notificationObservers = [NSObjectProtocol]()
// MARK: - 通知设置
/// 设置应用生命周期通知
private nonisolated func setupNotifications() {
// 使用nonisolated函数以避免actor隔离问题
let becomeActiveObserver = NotificationCenter.default.addObserver(
forName: UIApplication.didBecomeActiveNotification,
object: nil,
queue: .main
) { [weak self] _ in
guard let self = self else { return }
Task {
await self.handleAppDidBecomeActive()
}
}
let enterBackgroundObserver = NotificationCenter.default.addObserver(
forName: UIApplication.didEnterBackgroundNotification,
object: nil,
queue: .main
) { [weak self] _ in
guard let self = self else { return }
Task {
await self.handleAppDidEnterBackground()
}
}
// 存储观察者以便后续移除
notificationObservers = [becomeActiveObserver, enterBackgroundObserver]
}
// MARK: - 公共方法
/// 初始化BLE服务
/// - Returns: 是否初始化成功
func initialize() -> Bool {
if isInitialized {
return true
}
do {
// 初始化中央管理器 - 配置状态恢复选项
let options: [String: Any] = [
CBCentralManagerOptionRestoreIdentifierKey: restoreIdentifier,
CBCentralManagerOptionShowPowerAlertKey: true
]
centralManager = CBCentralManager(
delegate: CBManagerHandler.shared,
queue: nil,
options: options
)
CBManagerHandler.shared.bleService = self
isInitialized = true
os_log("BLE服务初始化成功", log: logger, type: .info)
return true
} catch {
os_log("BLE服务初始化失败: %{public}@", log: logger, type: .error, error.localizedDescription)
return false
}
}
/// 添加回调代理
/// - Parameter delegate: 要添加的代理
/// - Returns: 是否添加成功
func addDelegate(_ delegate: BleDelegate) -> Bool {
if !delegates.contains(where: { $0 === delegate }) {
delegates.append(delegate)
os_log("已添加BLE回调, 当前回调数: %d", log: logger, type: .debug, delegates.count)
return true
}
return false
}
/// 移除回调代理
/// - Parameter delegate: 要移除的代理
/// - Returns: 是否移除成功
func removeDelegate(_ delegate: BleDelegate) -> Bool {
if let index = delegates.firstIndex(where: { $0 === delegate }) {
delegates.remove(at: index)
os_log("已移除BLE回调, 当前回调数: %d", log: logger, type: .debug, delegates.count)
return true
}
return false
}
/// 清除所有回调代理
func clearDelegates() {
delegates.removeAll()
os_log("已清除所有BLE回调", log: logger, type: .debug)
}
/// 检查是否已连接
/// - Returns: 是否已连接
func isConnected() -> Bool {
return connectionState == BleConst.STATE_CONNECTED
}
// MARK: - 扫描方法
/// 开始主动扫描BLE设备
/// - Parameter timeout: 扫描超时时间(秒)
/// - Returns: 是否成功开始扫描
func startScan(timeout: TimeInterval = 15.0) -> Bool {
if !isInitialized {
os_log("BLE服务未初始化", log: logger, type: .error)
return false
}
if isScanning {
return false
}
guard let manager = centralManager, manager.state == .poweredOn else {
os_log("蓝牙未开启", log: logger, type: .error)
return false
}
os_log("开始主动扫描BLE设备...", log: logger, type: .info)
unregisterBackgroundScan() // 避免双重扫描
scanResults.removeAll()
// 扫描选项 - 允许重复结果,以获取最新的RSSI值
let options: [String: Any] = [
CBCentralManagerScanOptionAllowDuplicatesKey: true
]
// 设置过滤服务UUID
let scanFilters = [
// 如果需要过滤,添加CBUUID
// CBUUID(string: BleConst.PRIMARY_SERVICE_UUID.uuidString)
]
// 使用过滤器开始扫描
manager.scanForPeripherals(
withServices: scanFilters.isEmpty ? nil : scanFilters,
options: options
)
isScanning = true
// 设置扫描超时
scanTimeoutTask?.cancel()
scanTimeoutTask = Task { [weak self] in
guard let self = self else { return }
do {
try await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000))
if !Task.isCancelled {
await self.stopScan()
}
} catch {
// 任务被取消,忽略错误
}
}
return true
}
/// 停止主动扫描
/// - Returns: 是否成功停止扫描
func stopScan() -> Bool {
if !isScanning {
return false
}
os_log("停止主动扫描", log: logger, type: .info)
centralManager?.stopScan()
scanTimeoutTask?.cancel()
scanTimeoutTask = nil
isScanning = false
// 重新注册后台扫描,保证唤醒能力
registerBackgroundScan()
return true
}
/// 注册后台扫描
/// - Returns: 是否成功注册
func registerBackgroundScan() -> Bool {
// iOS中无法直接实现与Android相同的后台扫描唤醒功能
os_log("iOS不支持直接的后台扫描唤醒,将使用状态保存和恢复功能", log: logger, type: .info)
return true
}
/// 注销后台扫描
/// - Returns: 是否成功注销
func unregisterBackgroundScan() -> Bool {
// iOS没有直接的后台扫描注销机制
os_log("iOS不支持直接的后台扫描注销", log: logger, type: .info)
return true
}
// MARK: - 连接方法
/// 连接到指定地址的BLE设备
/// - Parameter address: 设备UUID字符串
func connect(address: String) async {
if connectionState == BleConst.STATE_CONNECTED {
os_log("已经连接中,忽略连接请求", log: logger, type: .warning)
return
}
guard let central = centralManager, central.state == .poweredOn else {
updateConnectionState(BleConst.STATE_ERROR)
return
}
// 关闭现有连接
disconnectGatt()
// 查找对应的外设
if let uuid = UUID(uuidString: address),
let targetPeripheral = scanResults.keys.first(where: { $0.identifier == uuid }) {
// 如果在扫描结果中找到,直接连接
os_log("从扫描结果中找到目标设备,开始连接...", log: logger, type: .debug)
await connectToPeripheral(targetPeripheral)
} else {
// 如果没有找到,尝试从已知设备中恢复
os_log("尝试使用UUID恢复设备连接: %{public}@", log: logger, type: .debug, address)
if let uuid = UUID(uuidString: address) {
let peripherals = central.retrievePeripherals(withIdentifiers: [uuid])
if let targetPeripheral = peripherals.first {
await connectToPeripheral(targetPeripheral)
} else {
os_log("未找到指定UUID的设备: %{public}@", log: logger, type: .error, address)
updateConnectionState(BleConst.STATE_ERROR)
}
} else {
os_log("无效的UUID格式: %{public}@", log: logger, type: .error, address)
updateConnectionState(BleConst.STATE_ERROR)
}
}
}
/// 连接到指定外设
/// - Parameter peripheral: 要连接的外设
private func connectToPeripheral(_ peripheral: CBPeripheral) async {
self.peripheral = peripheral
peripheral.delegate = CBPeripheralHandler.shared
CBPeripheralHandler.shared.bleService = self
updateConnectionState(BleConst.STATE_CONNECTING)
centralManager?.connect(peripheral, options: nil)
}
/// 断开当前连接
func disconnect() async {
guard let peripheral = peripheral, let central = centralManager else {
return
}
updateConnectionState(BleConst.STATE_DISCONNECTING)
central.cancelPeripheralConnection(peripheral)
}
/// 安全关闭GATT连接
private func disconnectGatt() {
if let peripheral = peripheral, let central = centralManager {
central.cancelPeripheralConnection(peripheral)
}
peripheral = nil
writeCharacteristic = nil
notifyCharacteristic = nil
audioCharacteristic = nil
}
/// 更新连接状态并通知回调
private func updateConnectionState(_ state: Int) {
connectionState = state
}
// MARK: - 设备通信方法
/// 获取设备版本号
/// - Returns: 是否成功发送请求
func getDeviceVersion() -> Bool {
return sendCommand(BleConst.CMD_GET_VERSION)
}
/// 获取电池信息
/// - Returns: 是否成功发送请求
func getBatteryInfo() -> Bool {
return sendCommand(BleConst.CMD_GET_BATTERY_INFO)
}
/// 打开编码器
/// - Returns: 是否成功发送请求
func openEncoder() -> Bool {
return sendCodecControl(BleConst.CODEC_CONTROL_ENCODE_ON)
}
/// 打开解码器
/// - Returns: 是否成功发送请求
func openDecoder() -> Bool {
return sendCodecControl(BleConst.CODEC_CONTROL_DECODE_ON)
}
/// 关闭编解码器
/// - Returns: 是否成功发送请求
func closeCodec() -> Bool {
return sendCodecControl(BleConst.CODEC_CONTROL_CLOSE)
}
/// 播放A2DP
/// - Returns: 是否成功发送请求
func playA2DP() -> Bool {
return sendCodecControl(BleConst.CODEC_CONTROL_A2DP_PLAY)
}
/// 发送编解码控制指令
/// - Parameter control: 控制值
/// - Returns: 是否成功发送
private func sendCodecControl(_ control: UInt8) -> Bool {
let data = Data([BleConst.APP_REQUEST_HEADER, BleConst.CMD_CONTROL_CODEC, control])
return writeData(data)
}
/// 发送命令
/// - Parameter command: 命令字
/// - Returns: 是否成功发送
private func sendCommand(_ command: UInt8) -> Bool {
let data = Data([BleConst.APP_REQUEST_HEADER, command])
return writeData(data)
}
/// 写入数据
/// - Parameter data: 要写入的数据
/// - Returns: 是否成功写入
private func writeData(_ data: Data) -> Bool {
guard let peripheral = peripheral,
let characteristic = writeCharacteristic,
connectionState == BleConst.STATE_CONNECTED else {
os_log("无法写入数据,设备未连接或特征未找到", log: logger, type: .error)
return false
}
let hexString = data.map { String(format: "0x%02X", $0) }.joined(separator: " ")
os_log("写入数据: %{public}@", log: logger, type: .debug, hexString)
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
return true
}
// MARK: - 数据处理方法
/// 处理音频数据
/// - Parameter data: 音频数据
func processAudioData(_ data: Data) async {
os_log("收到音频数据: %d字节", log: logger, type: .debug, data.count)
await notifyAudioDataReceived(data: data)
}
/// 处理设备响应
/// - Parameter data: 设备响应数据
func processDeviceResponse(_ data: Data) async {
guard data.count >= 2 else { return }
let cmd = data[1]
os_log("收到设备响应: CMD=0x%02X", log: logger, type: .debug, cmd)
switch cmd {
case BleConst.CMD_GET_VERSION:
if data.count >= 3 {
// 解析版本号
let version = String(format: "%d.%d.%d", data[2], data.count > 3 ? data[3] : 0, data.count > 4 ? data[4] : 0)
let infoData: [String: Any] = ["version": version]
await notifyDeviceInfoReceived(infoType: Int(cmd), infoData: infoData)
}
case BleConst.CMD_GET_BATTERY_INFO:
if data.count >= 3 {
// 解析电池电量
let batteryLevel = Int(data[2])
let infoData: [String: Any] = ["level": batteryLevel]
await notifyDeviceInfoReceived(infoType: Int(cmd), infoData: infoData)
}
default:
os_log("未处理的响应命令: 0x%02X", log: logger, type: .debug, cmd)
}
}
/// 处理设备通知
/// - Parameter data: 设备通知数据
func processDeviceNotification(_ data: Data) async {
guard data.count >= 2 else { return }
let notifyType = data[1]
os_log("收到设备通知: Type=0x%02X", log: logger, type: .debug, notifyType)
switch notifyType {
case BleConst.CMD_WAKE_UP:
// 设备唤醒信号
await notifyWakeupSignalReceived()
default:
os_log("未处理的通知类型: 0x%02X", log: logger, type: .debug, notifyType)
}
}
// MARK: - 应用状态处理
/// 处理应用进入活跃状态
private func handleAppDidBecomeActive() async {
os_log("应用进入活跃状态", log: logger, type: .debug)
// 重新初始化蓝牙管理器,如果需要
if centralManager == nil {
_ = initialize()
}
}
/// 处理应用进入后台
private func handleAppDidEnterBackground() async {
os_log("应用进入后台", log: logger, type: .debug)
// 在iOS中,后台蓝牙操作有一定限制,这里可以做一些清理工作
}
// MARK: - 回调通知方法
/// 通知扫描结果
/// - Parameter devices: 设备列表
func notifyScanResult(devices: [[String: Any]]) async {
let currentDelegates = delegates
for delegate in currentDelegates {
await MainActor.run {
delegate.onScanResult(devices: devices)
}
}
}
/// 通知连接状态变化
/// - Parameter state: 连接状态
func notifyConnectionStateChanged(state: Int) async {
let currentDelegates = delegates
for delegate in currentDelegates {
await MainActor.run {
delegate.onConnectionStateChanged(state: state)
}
}
}
/// 通知音频数据接收
/// - Parameter data: 音频数据
func notifyAudioDataReceived(data: Data) async {
let currentDelegates = delegates
for delegate in currentDelegates {
await MainActor.run {
delegate.onAudioDataReceived(data: data)
}
}
}
/// 通知唤醒信号接收
func notifyWakeupSignalReceived() async {
let currentDelegates = delegates
for delegate in currentDelegates {
await MainActor.run {
delegate.onWakeupSignalReceived()
}
}
}
/// 通知设备信息接收
/// - Parameters:
/// - infoType: 信息类型
/// - infoData: 信息数据
func notifyDeviceInfoReceived(infoType: Int, infoData: [String: Any]) async {
let currentDelegates = delegates
for delegate in currentDelegates {
await MainActor.run {
delegate.onDeviceInfoReceived(infoType: infoType, infoData: infoData)
}
}
}
/// 处理扫描到的设备
func handleDiscoveredPeripheral(_ peripheral: CBPeripheral, advertisementData: [String: Any], rssi: NSNumber) async {
// 打印外设信息
os_log("扫描到设备: 名称=%{public}@, ID=%{public}@, RSSI=%d", log: logger, type: .debug,
peripheral.name ?? "未知", peripheral.identifier.uuidString, rssi.intValue)
// 提取服务UUID
var uuids: [String] = []
if let serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] {
uuids = serviceUUIDs.map { $0.uuidString }
}
// 创建设备信息字典
let deviceInfo: [String: Any] = [
"id": peripheral.identifier.uuidString,
"name": peripheral.name ?? "未知",
"rssi": rssi.intValue,
"uuids": uuids
]
// 更新扫描缓存
scanResults[peripheral] = deviceInfo
// 通知扫描结果
await notifyScanResult(devices: [deviceInfo])
}
/// 处理连接结果
func handleConnectionResult(peripheral: CBPeripheral, success: Bool, error: Error?) async {
if success {
os_log("已连接到设备: %{public}@", log: logger, type: .info, peripheral.identifier.uuidString)
updateConnectionState(BleConst.STATE_CONNECTED)
// 开始服务发现
peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID])
} else {
os_log("连接设备失败: %{public}@", log: logger, type: .error, error?.localizedDescription ?? "未知错误")
updateConnectionState(BleConst.STATE_ERROR)
// 清理资源
self.peripheral = nil
}
}
/// 处理断开连接
func handleDisconnection(peripheral: CBPeripheral, error: Error?) async {
if let error = error {
os_log("设备连接断开(错误): %{public}@", log: logger, type: .error, error.localizedDescription)
updateConnectionState(BleConst.STATE_ERROR)
} else {
os_log("设备连接断开(正常)", log: logger, type: .info)
updateConnectionState(BleConst.STATE_DISCONNECTED)
}
// 清理资源
if self.peripheral?.identifier == peripheral.identifier {
self.peripheral = nil
self.writeCharacteristic = nil
self.notifyCharacteristic = nil
self.audioCharacteristic = nil
}
}
/// 处理发现服务
func handleDiscoveredServices(peripheral: CBPeripheral, error: Error?) async {
if let error = error {
os_log("发现服务失败: %{public}@", log: logger, type: .error, error.localizedDescription)
updateConnectionState(BleConst.STATE_ERROR)
return
}
guard let services = peripheral.services else {
os_log("没有发现任何服务", log: logger, type: .error)
updateConnectionState(BleConst.STATE_ERROR)
return
}
// 发现所有服务的特征
for service in services {
os_log("发现服务: %{public}@", log: logger, type: .debug, service.uuid.uuidString)
peripheral.discoverCharacteristics(nil, for: service)
}
}
/// 处理发现的特征
func handleDiscoveredCharacteristics(for service: CBService, peripheral: CBPeripheral, error: Error?) async {
if let error = error {
os_log("发现特征失败: %{public}@", log: logger, type: .error, error.localizedDescription)
return
}
guard let characteristics = service.characteristics else {
os_log("服务没有任何特征: %{public}@", log: logger, type: .warning, service.uuid.uuidString)
return
}
// 根据UUID识别和保存特征
for characteristic in characteristics {
os_log("发现特征: %{public}@", log: logger, type: .debug, characteristic.uuid.uuidString)
// 主服务特征
if service.uuid == BleConst.PRIMARY_SERVICE_UUID {
if characteristic.uuid == BleConst.WRITE_CHAR_UUID {
writeCharacteristic = characteristic
os_log("找到写入特征", log: logger, type: .debug)
} else if characteristic.uuid == BleConst.NOTIFY_CHAR_UUID {
notifyCharacteristic = characteristic
os_log("找到通知特征", log: logger, type: .debug)
// 设置通知
await setupNotification(for: characteristic, peripheral: peripheral)
}
}
// 音频服务特征
if service.uuid == BleConst.AUDIO_SERVICE_UUID {
if characteristic.uuid == BleConst.RECEIVE_AUDIO_CHAR_UUID {
audioCharacteristic = characteristic
os_log("找到音频特征", log: logger, type: .debug)
// 设置通知
await setupNotification(for: characteristic, peripheral: peripheral)
}
}
}
// 检查是否找到所有必要的特征
if writeCharacteristic == nil || notifyCharacteristic == nil {
os_log("未找到所有必要的特征", log: logger, type: .error)
updateConnectionState(BleConst.STATE_ERROR)
}
}
/// 设置特征的通知
/// - Parameters:
/// - characteristic: 特征
/// - peripheral: 外设
private func setupNotification(for characteristic: CBCharacteristic, peripheral: CBPeripheral) async {
if characteristic.properties.contains(.notify) {
peripheral.setNotifyValue(true, for: characteristic)
}
}
/// 处理特征值更新
func handleValueUpdate(for characteristic: CBCharacteristic, peripheral: CBPeripheral, error: Error?) async {
if let error = error {
os_log("特征值更新失败: %{public}@", log: logger, type: .error, error.localizedDescription)
return
}
guard let data = characteristic.value else {
os_log("特征没有值", log: logger, type: .warning)
return
}
let hexString = data.map { String(format: "%02X", $0) }.joined(separator: " ")
os_log("收到特征数据: %{public}@ - %{public}@", log: logger, type: .debug, characteristic.uuid.uuidString, hexString)
// 根据特征UUID处理不同类型的数据
if characteristic.uuid == BleConst.RECEIVE_AUDIO_CHAR_UUID {
// 音频数据处理
await processAudioData(data)
} else if characteristic.uuid == BleConst.NOTIFY_CHAR_UUID {
// 通知特征处理
if !data.isEmpty {
switch data[0] {
case BleConst.DEVICE_RESPONSE_HEADER:
// 设备响应
await processDeviceResponse(data)
case BleConst.DEVICE_NOTIFY_HEADER:
// 设备通知
await processDeviceNotification(data)
default:
os_log("未知数据类型: %d", log: logger, type: .debug, data[0])
}
}
}
}
// MARK: - 状态恢复处理
/// 处理蓝牙状态恢复
func handleStateRestoration(dict: [String: Any]) async {
os_log("正在恢复蓝牙状态...", log: logger, type: .info)
// 1. 恢复之前连接的外设
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] {
os_log("恢复 %d 个已连接的外设", log: logger, type: .debug, peripherals.count)
for peripheral in peripherals {
self.peripheral = peripheral
peripheral.delegate = CBPeripheralHandler.shared
CBPeripheralHandler.shared.bleService = self
// 根据外设当前状态采取不同操作
if peripheral.state == .connected {
os_log("外设 %{public}@ 已连接", log: logger, type: .debug, peripheral.identifier.uuidString)
updateConnectionState(BleConst.STATE_CONNECTED)
// 重新发现服务
peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID])
} else if peripheral.state == .connecting {
os_log("外设 %{public}@ 正在连接中", log: logger, type: .debug, peripheral.identifier.uuidString)
updateConnectionState(BleConst.STATE_CONNECTING)
} else {
os_log("外设 %{public}@ 状态异常: %d", log: logger, type: .debug, peripheral.identifier.uuidString, peripheral.state.rawValue)
// 尝试重新连接
updateConnectionState(BleConst.STATE_CONNECTING)
centralManager?.connect(peripheral, options: nil)
}
}
}
// 2. 恢复扫描状态
if let scanServices = dict[CBCentralManagerRestoredStateScanServicesKey] as? [CBUUID] {
os_log("恢复扫描任务,服务UUID数: %d", log: logger, type: .debug, scanServices.count)
let scanOptions = dict[CBCentralManagerRestoredStateScanOptionsKey] as? [String: Any] ?? [
CBCentralManagerScanOptionAllowDuplicatesKey: true
]
// 重新启动扫描任务
centralManager?.scanForPeripherals(
withServices: scanServices.isEmpty ? nil : scanServices,
options: scanOptions
)
isScanning = true
// 设置新的扫描超时(默认15秒)
scanTimeoutTask?.cancel()
scanTimeoutTask = Task { [weak self] in
guard let self = self else { return }
do {
try await Task.sleep(nanoseconds: UInt64(15.0 * 1_000_000_000))
if !Task.isCancelled {
await self.stopScan()
}
} catch {
// 任务被取消,忽略错误
}
}
}
// 通知外部:BLE状态已恢复
await notifyStateRestored()
}
/// 通知状态恢复
private func notifyStateRestored() async {
let currentDelegates = delegates
for delegate in currentDelegates {
if let stateDelegate = delegate as? BleStateRestorationDelegate {
await MainActor.run {
stateDelegate.onBleStateRestored()
}
}
}
}
}
// MARK: - 中央管理器委托处理器
class CBManagerHandler: NSObject, CBCentralManagerDelegate {
static let shared = CBManagerHandler()
weak var bleService: BleService?
func centralManagerDidUpdateState(_ central: CBCentralManager) {
Task {
guard let service = bleService else { return }
switch central.state {
case .poweredOn:
await MainActor.run {
os_log("蓝牙已开启", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .info)
}
case .poweredOff:
await MainActor.run {
os_log("蓝牙已关闭", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .warning)
}
await service.updateConnectionState(BleConst.STATE_DISCONNECTED)
case .unauthorized, .unsupported:
await MainActor.run {
os_log("蓝牙不可用: %d", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .error, central.state.rawValue)
}
await service.updateConnectionState(BleConst.STATE_ERROR)
default:
await MainActor.run {
os_log("蓝牙状态变化: %d", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug, central.state.rawValue)
}
}
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
Task {
await bleService?.handleDiscoveredPeripheral(peripheral, advertisementData: advertisementData, rssi: RSSI)
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
Task {
await bleService?.handleConnectionResult(peripheral: peripheral, success: true, error: nil)
}
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
Task {
await bleService?.handleConnectionResult(peripheral: peripheral, success: false, error: error)
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
Task {
await bleService?.handleDisconnection(peripheral: peripheral, error: error)
}
}
/// 状态恢复处理
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
os_log("蓝牙状态恢复被触发", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .info)
// 打印恢复信息
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] {
os_log("恢复外设数量: %d", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug, peripherals.count)
for (i, peripheral) in peripherals.enumerated() {
os_log("恢复外设[%d]: %{public}@", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug, i, peripheral.identifier.uuidString)
}
}
if let services = dict[CBCentralManagerRestoredStateScanServicesKey] as? [CBUUID] {
os_log("恢复扫描服务数量: %d", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug, services.count)
}
// 异步处理状态恢复
Task {
if let service = bleService {
await service.handleStateRestoration(dict: dict)
}
}
}
}
// MARK: - 外设委托处理器
class CBPeripheralHandler: NSObject, CBPeripheralDelegate {
static let shared = CBPeripheralHandler()
weak var bleService: BleService?
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
Task {
await bleService?.handleDiscoveredServices(peripheral: peripheral, error: error)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
Task {
await bleService?.handleDiscoveredCharacteristics(for: service, peripheral: peripheral, error: error)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
Task {
await bleService?.handleValueUpdate(for: characteristic, peripheral: peripheral, error: error)
}
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
os_log("写入特征值失败: %{public}@", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .error, error.localizedDescription)
} else {
os_log("写入特征值成功", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
os_log("设置通知状态失败: %{public}@", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .error, error.localizedDescription)
} else {
os_log("设置通知状态成功: %{public}@", log: OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleService"), type: .debug, characteristic.uuid.uuidString)
}
}
}
// MARK: - BLE状态恢复代理
/// 蓝牙状态恢复代理
protocol BleStateRestorationDelegate: AnyObject {
/// 当蓝牙状态被系统恢复时调用
func onBleStateRestored()
}
// MARK: - BLE代理
/// 蓝牙事件代理
protocol BleDelegate: AnyObject {
/// 扫描结果回调
func onScanResult(devices: [[String: Any]])
/// 连接状态变化回调
func onConnectionStateChanged(state: Int)
/// 音频数据接收回调
func onAudioDataReceived(data: Data)
/// 唤醒信号接收回调
func onWakeupSignalReceived()
/// 设备信息接收回调
func onDeviceInfoReceived(infoType: Int, infoData: [String: Any])
}