SDK minSdk 26→23,jvmTarget 17→11,确保老版本项目可消费 AAR。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
234 lines
6.0 KiB
Markdown
234 lines
6.0 KiB
Markdown
# Duooomi Android BLE SDK
|
||
|
||
Duooomi 蓝牙 BLE SDK 的 Android 版本。
|
||
|
||
## 环境要求
|
||
|
||
**SDK 集成要求(消费方最低版本):**
|
||
|
||
| 项目 | 最低要求 |
|
||
|------|---------|
|
||
| Kotlin | 1.9.0+ |
|
||
| AGP | 7.4.2+ |
|
||
| minSdk | 23 (Android 6.0) |
|
||
| JDK | 11+ |
|
||
|
||
**SDK 开发构建环境:**
|
||
|
||
| 项目 | 要求 |
|
||
|------|------|
|
||
| Android Studio | Hedgehog (2023.1.1) 或更高 |
|
||
| Kotlin | 1.9.22 |
|
||
| AGP | 8.2.2 |
|
||
| Gradle | 8.x |
|
||
| JDK | 17 |
|
||
| compileSdk / targetSdk | 34 |
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
duooomi-android-sdk/
|
||
├── sdk/ # SDK 库模块 (com.android.library)
|
||
│ └── src/main/kotlin/com/duooomi/ble/
|
||
│ ├── DuooomiBleSDK.kt # 公开 API 入口
|
||
│ ├── DuooomiBleConfig.kt # SDK 配置
|
||
│ ├── core/ # BLE 核心层 (BleClient, 类型定义, 错误类型)
|
||
│ ├── protocol/ # BLE 协议层 (帧格式, UUID, 协议管理)
|
||
│ ├── services/ # 服务层 (设备信息, 文件传输, ANI转换, 固件)
|
||
│ ├── models/ # 数据模型
|
||
│ └── utils/ # 日志工具
|
||
├── demo/ # 演示 App (Jetpack Compose)
|
||
└── build.gradle.kts
|
||
```
|
||
|
||
## 依赖
|
||
|
||
SDK 仅依赖一个外部库:
|
||
|
||
```
|
||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3
|
||
```
|
||
|
||
其余全部使用 Android 内置 API(BLE、JSON、HttpURLConnection)。
|
||
|
||
## 快速开始
|
||
|
||
### 1. 引入 SDK
|
||
|
||
在 `settings.gradle.kts` 中:
|
||
|
||
```kotlin
|
||
include(":sdk")
|
||
```
|
||
|
||
在 app 模块的 `build.gradle.kts` 中:
|
||
|
||
```kotlin
|
||
dependencies {
|
||
implementation(project(":sdk"))
|
||
}
|
||
```
|
||
|
||
### 2. 添加权限
|
||
|
||
在 `AndroidManifest.xml` 中添加:
|
||
|
||
```xml
|
||
<!-- Android 11 及以下 -->
|
||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
||
<!-- Android 12+ -->
|
||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||
<!-- 网络 (ANI转换/固件下载) -->
|
||
<uses-permission android:name="android.permission.INTERNET" />
|
||
|
||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
|
||
```
|
||
|
||
> **注意:** 运行时仍需动态申请 `BLUETOOTH_SCAN`、`BLUETOOTH_CONNECT`(Android 12+)和 `ACCESS_FINE_LOCATION` 权限。
|
||
|
||
### 3. 初始化 SDK
|
||
|
||
```kotlin
|
||
val sdk = DuooomiBleSDK(
|
||
context = this,
|
||
config = DuooomiBleConfig(
|
||
apiKey = "YOUR_API_KEY"
|
||
)
|
||
)
|
||
```
|
||
|
||
### 4. API Key 说明
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `apiKey` | **必填**。用于 ANI 转换和固件查询等后端 API 鉴权。|
|
||
| `apiHost` | 默认 `https://api.duooomi.com`,一般无需修改 |
|
||
| `cdnHost` | 默认 `https://cdn.bowong.cc/`,一般无需修改 |
|
||
| `firmwareIdentifier` | 默认 `duomi`,设备固件标识符 |
|
||
| `firmwareStatus` | 默认 `DRAFT`,可选 `PUBLISHED` |
|
||
| `aniWidth` | ANI 转换宽度,默认 `360` |
|
||
| `aniHeight` | ANI 转换高度,默认 `360` |
|
||
| `aniFps` | ANI 转换帧率,默认 `"24"` |
|
||
|
||
## API 参考
|
||
|
||
### 可观察状态 (StateFlow)
|
||
|
||
```kotlin
|
||
sdk.btState // ConnectionState: IDLE, SCANNING, CONNECTING, CONNECTED, ...
|
||
sdk.discoveredDevices // List<DiscoveredDevice>
|
||
sdk.connectedDevice // DiscoveredDevice?
|
||
sdk.deviceInfo // DeviceInfo?
|
||
sdk.version // String
|
||
sdk.isActivated // Boolean
|
||
sdk.transferProgress // Int (0-100)
|
||
sdk.error // String?
|
||
```
|
||
|
||
### 扫描与连接
|
||
|
||
```kotlin
|
||
// 开始扫描 (自动过滤 Duooomi 设备)
|
||
sdk.scan()
|
||
|
||
// 停止扫描
|
||
sdk.stopScan()
|
||
|
||
// 连接设备 (suspend)
|
||
val device = sdk.connect(deviceId)
|
||
|
||
// 断开连接 (suspend)
|
||
sdk.disconnect()
|
||
```
|
||
|
||
### 设备操作 (均需先连接)
|
||
|
||
```kotlin
|
||
// 获取设备信息
|
||
val info = sdk.getDeviceInfo()
|
||
// info.brand, info.name, info.size, info.powerlevel, info.freespace, info.allspace
|
||
|
||
// 获取固件版本
|
||
val versionInfo = sdk.getVersion()
|
||
// versionInfo.version, versionInfo.type
|
||
|
||
// 绑定设备
|
||
val bindResult = sdk.bind(userId)
|
||
// bindResult.sn, bindResult.contents (设备文件列表)
|
||
|
||
// 解绑设备
|
||
sdk.unbind(userId)
|
||
|
||
// 删除设备文件
|
||
sdk.deleteFile(fileKey)
|
||
```
|
||
|
||
### 文件传输
|
||
|
||
```kotlin
|
||
// 传输媒体文件 (自动转换为 ANI 格式)
|
||
// 支持: mp4, jpg, png, ani
|
||
sdk.transferMedia(fileUrl)
|
||
|
||
// 监听进度
|
||
sdk.transferProgress.collect { percent -> /* 0-100 */ }
|
||
```
|
||
|
||
### 固件升级
|
||
|
||
```kotlin
|
||
// 查询最新固件
|
||
val firmware = sdk.fetchLatestFirmware(identifier, status)
|
||
// firmware?.version, firmware?.fileUrl, firmware?.fileSize
|
||
|
||
// 检查是否有新版本 (对比版本号末尾10位时间戳)
|
||
val needUpdate = sdk.hasNewerFirmware(
|
||
deviceVersion = sdk.version.value, // 当前设备版本
|
||
serverVersion = firmware?.version // 服务端最新版本
|
||
)
|
||
// 参数为空/null/格式不合法时返回 false
|
||
|
||
// 执行 OTA 升级
|
||
sdk.upgradeFirmware(firmware.fileUrl)
|
||
```
|
||
|
||
### 错误处理
|
||
|
||
所有 suspend 方法在失败时抛出 `DuooomiBleError`:
|
||
|
||
```kotlin
|
||
try {
|
||
sdk.connect(deviceId)
|
||
} catch (e: DuooomiBleError.BluetoothNotPoweredOn) { /* 蓝牙未开启 */ }
|
||
catch (e: DuooomiBleError.ConnectionFailed) { /* 连接失败 */ }
|
||
catch (e: DuooomiBleError.NotConnected) { /* 未连接 */ }
|
||
catch (e: DuooomiBleError.Timeout) { /* 超时 */ }
|
||
catch (e: DuooomiBleError.PermissionDenied) { /* 权限不足 */ }
|
||
```
|
||
|
||
## 运行 Demo
|
||
|
||
```bash
|
||
# 构建
|
||
./gradlew :demo:assembleDebug
|
||
|
||
# 安装到设备
|
||
adb install demo/build/outputs/apk/debug/demo-debug.apk
|
||
```
|
||
|
||
## BLE 协议简述
|
||
|
||
- **Service UUID:** `000002c4-0000-1000-8000-00805f9b34fb`
|
||
- **Write Characteristic:** `000002c5-...`
|
||
- **Read Characteristic (Notify):** `000002c6-...`
|
||
- **帧格式:** `[head:1][type:1][subpageTotal:2][curPage:2][dataLen:2][data:N][checksum:1]`
|
||
- **校验和:** 二进制补码 `(~sum + 1) & 0xFF`
|
||
- **大数据分片:** 自动拆分,帧间延迟 35ms
|
||
|
||
## License
|
||
|
||
Proprietary - Duooomi
|