Files
duooomi-ios-sdk/README.md

224 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Duooomi BLE SDK (Native iOS)
纯原生 Swift 蓝牙 SDK使用 CoreBluetooth 直接操作,零第三方依赖。
## 架构设计
```
调用方 (宿主 App)
└── DuooomiBleSDK (ObservableObject) ← 公开 API + 状态观察
├── BleClient ← CoreBluetooth 封装
│ CBCentralManager / CBPeripheral
├── BleProtocolService ← 协议帧收发 + 分包重组
│ ProtocolManager (编码/解码/校验)
├── DeviceInfoService ← 设备命令 (JSON 请求/响应)
└── FileTransferService ← 文件下载 + 二进制传输
```
### 目录结构
```
Sources/DuooomiBleSDK/
├── DuooomiBleSDK.swift # 公开 API facade (ObservableObject)
├── Core/
│ ├── BleClient.swift # CoreBluetooth 封装 (scan/connect/write/notify)
│ └── BleTypes.swift # ConnectionState, DiscoveredDevice, DuooomiBleError
├── Protocol/
│ ├── ProtocolConstants.swift # BLE UUID, 帧常量, CommandType 枚举
│ ├── ProtocolFrame.swift # 协议帧结构体
│ └── ProtocolManager.swift # 帧编解码、校验和、分片/重组
├── Services/
│ ├── BleProtocolService.swift # 监听通知、解析帧、分包重组、帧发送
│ ├── DeviceInfoService.swift # 设备命令发送 (JSON payload)
│ └── FileTransferService.swift # 文件下载 + 二进制传输
└── Models/
├── DeviceInfo.swift # 设备信息 (allspace/freespace/brand/...)
├── VersionInfo.swift # 固件版本
├── BindingResponse.swift # 绑定响应 (sn/success/contents)
├── UnbindResponse.swift # 解绑响应
├── DeleteFileResponse.swift # 删除文件响应
└── PrepareTransferResponse.swift # 预传输响应
```
### 协议帧格式
```
[head:1][type:1][subpageTotal:2][curPage:2][dataLen:2][data:N][checksum:1]
```
| 字段 | 大小 | 说明 |
|------|------|------|
| head | 1 byte | 方向标识: APP→Device=0xC7, Device→APP=0xB0 |
| type | 1 byte | 命令类型 (CommandType 枚举) |
| subpageTotal | 2 bytes | 总分包数 (0=单帧) |
| curPage | 2 bytes | 当前包序号 (从 total-1 倒数到 0) |
| dataLen | 2 bytes | 数据段长度 |
| data | N bytes | 数据内容 (JSON 或二进制) |
| checksum | 1 byte | 校验: (~字节和 + 1) & 0xFF |
### 请求-响应模式
```swift
// CheckedContinuation
let info = try await sdk.getDeviceInfo() // 10s
```
内部流程:
1. 注册 continuation (keyed by commandType)
2. 编码 JSON → 创建协议帧 → 写入 write characteristic
3. 设备回包 → notify → 解析帧 → 分包重组 → 匹配 continuation → resume
---
## 功能清单
### 扫描
| 方法 | 说明 |
|------|------|
| `scan()` | 开始扫描,结果通过 `discoveredDevices` 属性观察 (500ms 批量刷新) |
| `stopScan()` | 停止扫描 |
### 连接
| 方法 | 说明 |
|------|------|
| `connect(deviceId:) async throws -> DiscoveredDevice` | 连接设备 (含服务发现 + 特征发现 + notify 启用) |
| `disconnect() async throws` | 断开连接,清理所有状态 |
### 设备命令 (请求-响应10s 超时)
| 方法 | 发送 payload | 响应类型 |
|------|-------------|---------|
| `getDeviceInfo()` | `{"type":13}` | `DeviceInfo` |
| `getVersion()` | `{"type":7}` | `VersionInfo` |
| `bind(userId:)` | `{"type":15,"userId":"..."}` | `BindingResponse` |
| `unbind(userId:)` | `{"type":18,"userId":"..."}` | `UnbindResponse` |
| `deleteFile(key:)` | `{"type":19,"key":"..."}` | `DeleteFileResponse` |
| `prepareTransfer(key:size:)` | `{"type":20,"key":"...","size":N}` | `PrepareTransferResponse` |
### 文件传输
| 方法 | 说明 |
|------|------|
| `transferFile(fileUri:commandType:) async throws` | 下载文件 + 分帧传输,进度通过 `transferProgress` 观察 |
### 可观察状态
| 属性 | 类型 | 说明 |
|------|------|------|
| `btState` | `ConnectionState` | idle/scanning/connecting/connected/disconnecting/disconnected |
| `discoveredDevices` | `[DiscoveredDevice]` | 扫描发现的设备列表 |
| `connectedDevice` | `DiscoveredDevice?` | 当前连接的设备 |
| `deviceInfo` | `DeviceInfo?` | 设备信息 (空间/品牌/电量等) |
| `version` | `String` | 固件版本 |
| `isActivated` | `Bool` | 是否已绑定 |
| `transferProgress` | `Int` | 传输进度 0-100 |
| `error` | `String?` | 最近的错误信息 |
### CommandType 枚举
| Case | 值 | 用途 |
|------|-----|------|
| `.otaPackage` | 0x02 | OTA 升级包 |
| `.transferBootAnimation` | 0x03 | 开机动画 |
| `.transferAniVideo` | 0x05 | ANI 视频 (默认) |
| `.transferJpegImage` | 0x06 | JPEG 图片 |
| `.getDeviceVersion` | 0x07 | 获取固件版本 |
| `.getDeviceInfo` | 0x0D | 获取设备信息 |
| `.bindDevice` | 0x0F | 绑定设备 |
| `.unbindDevice` | 0x12 | 解绑设备 |
| `.deleteFile` | 0x13 | 删除文件 |
| `.prepareTransfer` | 0x14 | 预传输检查 |
---
## 集成方式
### Swift Package Manager (推荐)
```swift
// Package.swift
dependencies: [
.package(path: "../duooomi-ios-sdk")
]
//
dependencies: [
.package(url: "https://github.com/xxx/duooomi-ios-sdk.git", from: "1.0.0")
]
```
### 使用示例
```swift
import DuooomiBleSDK
@main
struct MyApp: App {
@StateObject private var sdk = DuooomiBleSDK()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(sdk)
}
}
}
struct ContentView: View {
@EnvironmentObject var sdk: DuooomiBleSDK
var body: some View {
VStack {
Text("State: \(sdk.btState.rawValue)")
Button("Scan") { sdk.scan() }
ForEach(sdk.discoveredDevices) { device in
Button(device.name ?? device.id) {
Task {
try await sdk.connect(deviceId: device.id)
let info = try await sdk.getDeviceInfo()
print("Device: \(info.brand)")
}
}
}
}
}
}
```
### Info.plist 权限
```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to communicate with your device</string>
```
---
## 技术规格
- **平台**: iOS 16.0+
- **语言**: Swift 5.9+
- **依赖**: 零 (仅 CoreBluetooth 系统框架)
- **分发**: SPM / XCFramework
- **线程模型**: 公开 API 为 @MainActorBLE 操作在专用串行队列
## 与旧 Brownfield SDK 对比
| 维度 | Brownfield | 原生 SDK |
|------|-----------|---------|
| 体积 | ~75MB (含 Hermes + RN) | ~几百KB |
| 构建 | 7 个 patch + prebuild + pod | `swift build` |
| 类型安全 | `[String: Any]` 字典 | 强类型 struct/enum |
| API | 回调 + 消息传递 | `async throws` |
| 调试 | JS + Native 两层 | 纯 Xcode 断点 |
| 依赖 | React Native, Hermes, Expo | CoreBluetooth (系统框架) |