主要改动: - 新增 fetchLatestFirmware/upgradeFirmware/tryReportPendingUpgrade 三段 OTA 接口,对齐 expo bindDeviceWithOrchestration 行为 - bind 仅做硬绑+getVersion,软绑/对账上报/拉最新固件搬到 fetchLatestFirmware 内部串;软绑失败自动硬解回滚 - UpgradeRecord 复合主键 (sn, firmwareId) 持久化 + sn 级 in-flight 互斥 - DuooomiBleSDKDelegate 新增 didUpdateUpgradeRecords,集成方 可观察对账上报结果(reported/outcome 状态) - DuooomiBleSDK 主类按职责拆 5 个 extension 文件,公开 API 不变 - TargetFirmware 简化为只取必要字段 + 新增 forceUpgrade - scanNamePrefix 改为必填 String - demo 秘钥移至本地 DemoSecrets.swift (gitignored) - README 重写:完整 OTA 流程示例 + 上报状态判定表 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
91 lines
3.7 KiB
Swift
91 lines
3.7 KiB
Swift
import Foundation
|
||
|
||
// MARK: - Connection
|
||
|
||
extension DuooomiBleSDK {
|
||
|
||
/// 连接到指定设备。
|
||
///
|
||
/// 内部会停止扫描、启动协议监听。成功后 `sdk.btState = .connected`,`sdk.connectedDevice` 写入;
|
||
/// delegate `didConnectDevice` 回调到达。后续可调用 `getVersion` / `getDeviceInfo` / `bind` 等。
|
||
///
|
||
/// - Parameters:
|
||
/// - deviceId: 设备 UUID(从 `discoveredDevices.id` 取,对应 `CBPeripheral.identifier.uuidString`)
|
||
/// - completion: 回调 `Result<DiscoveredDevice, Error>`
|
||
/// - 成功:连接上的 `DiscoveredDevice`
|
||
/// - 失败:`.connectionFailed(...)` / `.serviceNotFound` / `.characteristicNotFound`
|
||
/// / `.bluetoothNotPoweredOn(...)` / `.permissionDenied`
|
||
public func connect(deviceId: String, completion: @escaping (Result<DiscoveredDevice, Error>) -> Void) {
|
||
stopScan()
|
||
btState = .connecting
|
||
BleLog.i("Connecting to \(deviceId)...", "Connect")
|
||
|
||
bleClient.connect(deviceId: deviceId) { [weak self] result in
|
||
guard let self = self else { return }
|
||
switch result {
|
||
case .success(let peripheral):
|
||
self.protocolService.startListening()
|
||
|
||
let device = DiscoveredDevice(
|
||
id: peripheral.identifier.uuidString,
|
||
name: peripheral.name,
|
||
rssi: 0
|
||
)
|
||
self.connectedDevice = device
|
||
self.btState = .connected
|
||
BleLog.i("Connected: \(device.id)", "Connect")
|
||
completion(.success(device))
|
||
|
||
case .failure(let error):
|
||
self.btState = .idle
|
||
self.error = error.localizedDescription
|
||
BleLog.e("Connect failed: \(error.localizedDescription)", "Connect")
|
||
completion(.failure(error))
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 断开当前 BLE 连接。
|
||
///
|
||
/// 同步清空 `sdk.connectedDevice` / `deviceInfo` / `version` / `isActivated`,停止协议监听,
|
||
/// 取消所有 pending RPC 回调(这些回调会收到 `.notConnected` 失败)。
|
||
///
|
||
/// - Parameter completion: 回调 `Result<Void, Error>`
|
||
/// - 成功:已断开
|
||
/// - 失败:CoreBluetooth 底层错误(极少见)
|
||
public func disconnect(completion: @escaping (Result<Void, Error>) -> Void) {
|
||
btState = .disconnecting
|
||
BleLog.i("Disconnect requested", "Connect")
|
||
protocolService.stopListening()
|
||
cancelAllPending(error: DuooomiBleError.notConnected)
|
||
|
||
bleClient.disconnect { [weak self] result in
|
||
guard let self = self else { return }
|
||
if case .failure(let error) = result {
|
||
self.error = error.localizedDescription
|
||
BleLog.e("Disconnect error: \(error.localizedDescription)", "Connect")
|
||
}
|
||
|
||
self.connectedDevice = nil
|
||
self.deviceInfo = nil
|
||
self.version = ""
|
||
self.isActivated = false
|
||
self.btState = .disconnected
|
||
BleLog.i("Disconnected", "Connect")
|
||
completion(result)
|
||
}
|
||
}
|
||
|
||
/// 返回 iOS 系统当前已连接的、和本 SDK 服务 UUID 匹配的设备列表。
|
||
///
|
||
/// 用于断网后重启 App、设备仍在系统蓝牙连接列表里的快速恢复场景。
|
||
/// 不需要先 `scan()`,对每个返回的 `DiscoveredDevice.id` 直接 `connect(deviceId:)` 即可。
|
||
///
|
||
/// - Returns: 系统已连接的 `DiscoveredDevice` 数组(可能为空)
|
||
public func getConnectedDevices() -> [DiscoveredDevice] {
|
||
let list = bleClient.retrieveConnectedDevices()
|
||
BleLog.d("System-connected devices: \(list.count)", "Connect")
|
||
return list
|
||
}
|
||
}
|