demo app + SDK updates:\n- Add direct ANI transfer (prepare -> transfer)\n- Add firmware update flow (fetch latest w/ x-api-key, OTA transfer)\n- Extract x-api-key to NetworkConstants\n- Rename example app to demo; move folder and entry to DemoApp\n- Switch from SPM package dependency to local framework target\n- Enable automatic Info.plist generation for framework target\n- Add placeholder test to satisfy SwiftPM test target\n- Regenerate XcodeGen project (demo.xcodeproj)
This commit is contained in:
261
README.md
261
README.md
@@ -1,52 +1,223 @@
|
||||
# DuooomiTest
|
||||
# Duooomi BLE SDK (Native iOS)
|
||||
|
||||
DuooomiBleSDK 的 iOS 测试应用,用于验证蓝牙设备的扫描、连接、绑定、文件传输等功能。
|
||||
纯原生 Swift 蓝牙 SDK,使用 CoreBluetooth 直接操作,零第三方依赖。
|
||||
|
||||
## 环境要求
|
||||
|
||||
- Xcode 26+
|
||||
- iOS 16.0+
|
||||
- Swift 6.0
|
||||
- [XcodeGen](https://github.com/yonaskolb/XcodeGen)
|
||||
|
||||
## 项目依赖
|
||||
|
||||
- `DuooomiBleSDK.xcframework` — 蓝牙通信 SDK
|
||||
- `hermesvm.xcframework` — JS 运行时
|
||||
|
||||
依赖文件位于 `../duooomi-ble-sdk/artifacts/`,请确保该路径下存在对应的 xcframework。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 1. 安装 XcodeGen(如果还没有)
|
||||
brew install xcodegen
|
||||
|
||||
# 2. 生成 Xcode 项目
|
||||
xcodegen generate
|
||||
|
||||
# 3. 打开项目
|
||||
open DuooomiTest.xcodeproj
|
||||
```
|
||||
|
||||
在 Xcode 中设置你的 `DEVELOPMENT_TEAM`,然后运行到真机即可(蓝牙功能需要真机调试)。
|
||||
|
||||
## 项目结构
|
||||
## 架构设计
|
||||
|
||||
```
|
||||
├── project.yml # XcodeGen 配置
|
||||
├── DuooomiTest/
|
||||
│ ├── Info.plist
|
||||
│ └── Sources/
|
||||
│ ├── DuooomiTestApp.swift # App 入口
|
||||
│ ├── ContentView.swift # 测试界面
|
||||
│ └── SDKManager.swift # SDK 封装层
|
||||
调用方 (宿主 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 为 @MainActor,BLE 操作在专用串行队列
|
||||
|
||||
## 与旧 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 (系统框架) |
|
||||
|
||||
Reference in New Issue
Block a user