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

请求-响应模式

// 发送命令 → 注册 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 (推荐)

// Package.swift
dependencies: [
    .package(path: "../duooomi-ios-sdk")
]

// 或远程
dependencies: [
    .package(url: "https://github.com/xxx/duooomi-ios-sdk.git", from: "1.0.0")
]

使用示例

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 权限

<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 (系统框架)
Description
No description provided
Readme 211 KiB
Languages
Swift 99.4%
Ruby 0.6%