feat: 重写 SDK 支持 iOS 12.2,移除 async/await 和 Combine

- 所有公开 API 改为 completion handler (Result<T, Error>)
- 状态通知改为 DuooomiBleSDKDelegate 协议
- 移除 Sendable、@MainActor、AsyncStream、CheckedContinuation
- 网络请求改为 URLSession.dataTask 回调
- BLE 通信改为 delegate + 闭包模式
- deployment target 降至 iOS 12.2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
km2023
2026-04-16 16:59:39 +08:00
parent 79af43cdef
commit 1a7bbdc625
26 changed files with 3211 additions and 944 deletions

130
README.md
View File

@@ -28,70 +28,119 @@ let sdk = DuooomiBleSDK(config: .init(
apiKey: "your-api-key" //
// apiHost: URL(...)!, // https://api.duooomi.com
// cdnHost: "https://cdn.bowong.cc/", //
// firmwareIdentifier: "duomi", //
// firmwareStatus: "DRAFT" //
// aniWidth: 360, // ANI 360
// aniHeight: 360, // ANI 360
// aniFps: "24", // ANI 24
// firmwareIdentifier: "duomi", //
// firmwareStatus: "DRAFT" //
))
//
sdk.delegate = self
```
## 代理Delegate
通过 `DuooomiBleSDKDelegate` 接收状态变化,所有方法在主线程调用,均有默认空实现:
```swift
extension ViewController: DuooomiBleSDKDelegate {
func sdk(_ sdk: DuooomiBleSDK, didChangeState state: ConnectionState) { }
func sdk(_ sdk: DuooomiBleSDK, didUpdateDevices devices: [DiscoveredDevice]) { }
func sdk(_ sdk: DuooomiBleSDK, didConnectDevice device: DiscoveredDevice?) { }
func sdk(_ sdk: DuooomiBleSDK, didUpdateDeviceInfo info: DeviceInfo?) { }
func sdk(_ sdk: DuooomiBleSDK, didUpdateVersion version: String) { }
func sdk(_ sdk: DuooomiBleSDK, didChangeActivation isActivated: Bool) { }
func sdk(_ sdk: DuooomiBleSDK, didUpdateProgress progress: Int) { }
func sdk(_ sdk: DuooomiBleSDK, didEncounterError error: String?) { }
}
```
## API
所有异步方法使用 `completion` 回调,返回 `Result<T, Error>`
### 扫描
| 方法 | 返回 | 说明 |
|------|------|------|
| `scan()` | `Void` | 开始扫描,结果通过 `discoveredDevices` 观察 |
| `stopScan()` | `Void` | 停止扫描 |
| 方法 | 说明 |
|------|------|
| `scan()` | 开始扫描,结果通过 delegate `didUpdateDevices` 回调 |
| `stopScan()` | 停止扫描 |
### 连接
| 方法 | 返回 | 说明 |
|------|------|------|
| `connect(deviceId: String)` | `DiscoveredDevice` | 连接设备 |
| `disconnect()` | `Void` | 断开连接 |
| `getConnectedDevices()` | `[DiscoveredDevice]` | 获取系统已连接设备 |
```swift
sdk.connect(deviceId: deviceId) { result in
switch result {
case .success(let device): print("Connected: \(device.name ?? device.id)")
case .failure(let error): print("Failed: \(error)")
}
}
sdk.disconnect { result in
// ...
}
```
### 设备命令
| 方法 | 返回 | 说明 |
|------|------|------|
| `getDeviceInfo()` | `DeviceInfo` | 品牌、容量、电量、型号 |
| `getVersion()` | `VersionInfo` | 固件版本 |
| `bind(userId: String)` | `BindingResponse` | 绑定设备,返回 sn + 文件列表。**绑定后才能查看设备文件** |
| `unbind(userId: String)` | `UnbindResponse` | 解绑设备。**解绑后该账号的设备文件将被删除** |
| `deleteFile(key: String)` | `DeleteFileResponse` | 删除设备上的单个文件 |
```swift
sdk.getDeviceInfo { result in
if case .success(let info) = result {
print("Brand: \(info.brand), Power: \(info.powerlevel)%")
}
}
sdk.getVersion { result in
if case .success(let info) = result {
print("Version: \(info.version)")
}
}
sdk.bind(userId: "user-id") { result in
if case .success(let resp) = result {
print("SN: \(resp.sn), Files: \(resp.contents.count)")
}
}
sdk.unbind(userId: "user-id") { result in /* ... */ }
sdk.deleteFile(key: "file-key") { result in /* ... */ }
```
### 文件传输
| 方法 | 返回 | 说明 |
|------|------|------|
| `transferMedia(fileUrl: String)` | `Void` | 输入文件 URLmp4/jpg/png内部自动完成 ANI 转换 → prepare → 传输。进度通过 `transferProgress` 观察 |
```swift
// ANI prepare transfer
sdk.transferMedia(fileUrl: "https://example.com/video.mp4") { result in
switch result {
case .success: print("Transfer complete")
case .failure(let error): print("Transfer failed: \(error)")
}
}
// delegate didUpdateProgress
```
### 固件升级
| 方法 | 返回 | 说明 |
|------|------|------|
| `fetchLatestFirmware(identifier:status:)` | `FirmwareInfo?` | 查询最新固件nil 表示无可用版本 |
| `hasNewerFirmware(deviceVersion:serverVersion:)` | `Bool` | 对比版本号末尾10位时间戳判断是否有新版本。参数无效返回 false |
| `upgradeFirmware(fileUrl: String)` | `Void` | OTA 传输固件包到设备 |
```swift
// 1.
let info = try await sdk.fetchLatestFirmware()
sdk.fetchLatestFirmware { result in
guard case .success(let info?) = result else { return }
// 2.
let needUpdate = sdk.hasNewerFirmware(
deviceVersion: sdk.version, //
serverVersion: info?.version //
)
// 2.
let needUpdate = sdk.hasNewerFirmware(
deviceVersion: sdk.version,
serverVersion: info.version
)
// 3. OTA
try await sdk.upgradeFirmware(fileUrl: info.fileUrl)
// 3. OTA
if needUpdate {
sdk.upgradeFirmware(fileUrl: info.fileUrl) { result in /* ... */ }
}
}
```
### 可观察状态
### 可读取状态
| 属性 | 类型 | 说明 |
|------|------|------|
@@ -124,8 +173,8 @@ public struct DeviceInfo {
let brand: String //
let size: String //
let powerlevel: Int //
let allspace: Int //
let freespace: Int //
let allspace: UInt64 //
let freespace: UInt64 //
}
// BindingResponse bind
@@ -145,5 +194,6 @@ public struct BindingResponse {
## 技术规格
- iOS 16.0+ / Swift 5.9+ / 零依赖
- 公开 API @MainActorBLE 操作专用串行队列
- iOS 12.2+ / Swift 5.0+ / 零依赖
- Delegate 回调模式,所有状态变化在主线程通知
- BLE 操作专用串行队列