flutter_sdk/README.md

381 lines
14 KiB
Markdown
Raw Normal View History

2026-09-09 16:20:05 +08:00
# Flutter SDK
2026-08-20 09:25:05 +08:00
Flutter 智能锁接入 SDK。SDK 封装了星云账户、蓝牙扫描和配对、锁管理、凭证管理、网关 WiFi 配网、锁状态/设置,以及视频对讲信令与媒体数据事件。
> 当前交付面向 Android 和 iOS;不提供 macOS、Windows、Linux 或 Web 的桌面端支持。
## 交付内容
实际交付根目录包含下列五个同级目录。`flutter_sdk` 通过相对路径依赖前三个底层包;`video_decode_plugin` 是示例工程的视频渲染可选组件:
```text
vendor/
├── flutter_sdk/ # 本 SDK
├── starlock_ble/ # 蓝牙协议与设备连接层
├── starcloud/ # 云端、设备与领域模型
├── starchart/ # 视频对讲信令与传输层
└── video_decode_plugin/ # 可选:示例使用的 H264 FFmpeg 渲染插件
```
`example/` 是可运行的集成示例,覆盖常用的接入路径。不要将示例中的测试账号、日志或 UI 直接用于生产环境。
## 环境与平台要求
| 项目 | 要求 |
| --- | --- |
| Flutter | 3.19.6 或更高版本 |
| Dart | 3.3.0 或更高版本 |
| Android | `minSdkVersion 23`,真机蓝牙调试 |
| iOS | iOS 12.0 或更高版本,真机调试 |
| 网络 | 可访问已获授权的星云服务和视频对讲服务 |
蓝牙扫描、配对、门锁控制、WiFi 配网、麦克风和相机相关能力均需要在真机验证。模拟器不具备完整的蓝牙能力。
## 安装
将 `flutter_sdk`、`starlock_ble`、`starcloud`、`starchart` 放入宿主 App 的 `vendor/`。需要使用示例同款 FFmpeg 视频渲染时,再一并放入 `video_decode_plugin`。
宿主 `pubspec.yaml` 的最小依赖只需要声明 `flutter_sdk`:
```yaml
dependencies:
flutter:
sdk: flutter
flutter_sdk:
path: vendor/flutter_sdk
```
`flutter_sdk` 的 `pubspec.yaml` 已通过 `path: ../starlock_ble`、`../starcloud`、`../starchart` 引用同级底层包,因此宿主执行一次依赖安装即可递归解析全部核心包:
```bash
fvm flutter pub get
```
如需将示例的 H264 FFmpeg 解码渲染带入宿主 App,额外声明:
```yaml
video_decode_plugin:
path: vendor/video_decode_plugin
```
然后仍只需要在宿主 App 根目录再执行一次 `fvm flutter pub get`。**不需要**为正常集成专门进入 `video_decode_plugin`、`starlock_ble`、`starcloud` 或 `starchart` 逐个执行 `pub get`;只有开发/测试这些包自身或运行它们的独立 example 时才需要。
如果项目不使用 FVM,请使用与本 SDK 兼容的 Flutter 版本执行 `flutter pub get`。
## 平台配置
### Android
确认 `android/app/build.gradle` 的最小版本不低于 23,并在 `android/app/src/main/AndroidManifest.xml` 添加按业务实际需要的权限:
```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<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" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
```
- 仅使用锁管理时,麦克风、相机权限可不声明。
- Android 12 及以上需要在运行时申请 `BLUETOOTH_SCAN`、`BLUETOOTH_CONNECT`。
- 若视频对讲服务使用 `http://` 地址,Android 需要允许明文流量;生产环境建议使用 HTTPS。
### iOS
在 `ios/Podfile` 中设置:
```ruby
platform :ios, '12.0'
```
在 `ios/Runner/Info.plist` 添加适合实际业务的用途说明:
```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>用于扫描和连接智能锁。</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>用于连接智能锁设备。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>用于发现附近的蓝牙智能锁。</string>
<key>NSMicrophoneUsageDescription</key>
<string>用于视频对讲。</string>
<key>NSCameraUsageDescription</key>
<string>用于视频对讲和扫码功能。</string>
```
完成后执行:
```bash
cd ios && pod install && cd ..
```
## 接入顺序
常规业务建议严格按以下顺序执行:
```text
bootstrap
→ auth.init
→ createCloudUser / setCloudAccounts
→ 扫描、配对或获取锁列表
→ 构建 StarCloudLockContext
→ 锁控制、凭证、WiFi 配网或视频对讲
```
`CloudUserInfo` 是扫描、配对及云端锁管理的前提;`lock.skychip.top` 的 WiFi 授权登录令牌仅用于网关配网,不能替代 SDK 云账户。
## 快速接入
### 1. 创建客户端并初始化认证
应用启动时只调用一次 `bootstrap()`:
```dart
import 'package:flutter/widgets.dart';
import 'package:flutter_sdk/starcloud_flutter_sdk.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
StarCloudClient.bootstrap();
runApp(const MyApp());
}
```
从星云后台注册应用并获取 `clientId`、`clientSecret`。不要把密钥提交到代码仓库;建议由业务后端下发或通过构建参数注入:
```dart
const clientId = String.fromEnvironment('STARCLOUD_CLIENT_ID');
const clientSecret = String.fromEnvironment('STARCLOUD_CLIENT_SECRET');
const environmentUrl = String.fromEnvironment('STARCLOUD_ENV_URL');
StarCloudClient.instance.auth.init(
clientId: clientId,
clientSecret: clientSecret,
environmentUrl: environmentUrl,
);
```
例如:
```bash
fvm flutter run \
--dart-define=STARCLOUD_CLIENT_ID=your_client_id \
--dart-define=STARCLOUD_CLIENT_SECRET=your_client_secret \
--dart-define=STARCLOUD_ENV_URL=https://your-authorized-host
```
### 2. 设置 SDK 云账户
生产环境应由业务后台保存、恢复并下发合法的 `CloudUserInfo`。仅在联调或示例中,可创建临时云账户:
```dart
final cloudUser = await StarCloudClient.instance.auth.createCloudUser();
StarCloudClient.instance.auth.setCloudAccounts([cloudUser]);
```
若有多个云账户,使用 `setCloudAccounts` 一次性设置,并在设备业务 API 中按需传入 `cloudUid`。
### 3. 扫描、配对与锁控制
```dart
final devices = await StarCloudClient.instance.device.scanDeviceList(
timeout: 10,
onScan: (list) {
// 可持续刷新扫描列表
},
);
if (devices.isEmpty) return;
final lock = await StarCloudClient.instance.device.pairDevice(
scanResult: devices.first,
);
await StarCloudClient.instance.device.openLock(lockId: lock.lockId);
await StarCloudClient.instance.device.closeLock(lockId: lock.lockId);
```
扫描页应直接为每个扫描结果提供“配对”操作;若本地已配对锁的 `mac` 或蓝牙设备名与扫描结果一致,应展示“已配对”而非再次配对。离开页面或用户取消时调用:
```dart
await StarCloudClient.instance.device.stopScan();
await StarCloudClient.instance.device.disconnect();
```
已配对设备可从云端获取:
```dart
final list = await StarCloudClient.instance.device.getDeviceList(
pageNo: 1,
pageSize: 20,
);
final latestLock = await StarCloudClient.instance.device.getDevice(
lockId: lock.lockId,
);
```
### 4. 使用 `StarCloudLockContext`
高级 BLE 接口(状态、功能位、网关配网)需要锁身份、蓝牙密钥和本地握手 token。请从已配对或已查询到的 `StarCloudLock` 构建上下文,不要自行拼装密钥:
```dart
final context = await StarCloudLockContext.fromLock(latestLock);
final state = await StarCloudClient.instance.lockState
.readLockStateByContext(context);
await StarCloudClient.instance.lockSetting.setRemoteUnlockByContext(
context,
enabled: true,
);
```
上下文依赖已经完成的蓝牙认证握手;token 缺失或过期时,应重新连接/配对并获取最新锁信息后重试。
### 5. 网关 WiFi 配网
网关配网需要:已配对的网关锁、SDK 云账户、锁主账号或管理员账号的 WiFi 授权令牌,以及 App 视频对讲 PeerID。
先登录 WiFi 授权服务:
```dart
final accessToken = await StarCloudClient.instance.auth.loginLockService(
username: username,
password: password,
deviceBrand: 'android',
deviceModel: 'model-name',
deviceVersion: 'os-version',
);
```
初始化视频对讲以取得 App PeerID(见下一节),随后执行:
```dart
final context = await StarCloudLockContext.fromLock(lock);
final reply = await StarCloudClient.instance.wifi.configureWifiByContext(
context,
ssid: ssid,
password: password,
lockServiceAccessToken: accessToken,
deviceName: lock.bluetooth.bluetoothDeviceName,
mac: lock.mac,
);
// 配网响应包含锁端 peerId;仍需轮询云端确认锁上线。
final status = await StarCloudClient.instance.wifi.getGatewayStatus(
lockId: lock.bluetooth.bluetoothDeviceName,
userId: context.userId,
deviceName: lock.bluetooth.bluetoothDeviceName,
mac: lock.mac,
);
```
`configureWifiByContext` 会获取网关配置、通过 BLE 下发,并向云端提交设备网络信息。BLE 返回成功只表示流程已接受,不代表锁已联网;请使用 `getDevice(lockId: ...)` 轮询 `isOnline` 与 `peerId`。
### 6. 视频对讲
视频对讲服务只负责注册、呼叫和事件分发;H264 解码渲染、G711 编解码、麦克风采集与权限处理由宿主 App 集成。示例工程使用本地 `video_decode_plugin` 的 FFmpeg 后端进行 H264 解码渲染。
```dart
await StarCloudClient.instance.talk.init(
productName: 'YourApp',
unique: deviceUniqueId,
baseUrl: 'http://scd.skychip.top:8710',
);
final appPeerId = StarCloudClient.instance.talk.myPeerId;
```
先订阅事件,再响应来电、视频协商与状态:
```dart
final incomingSub = StarCloudClient.instance.talk.onIncomingCall.listen((call) {
// 展示接听/拒绝 UI
});
final mediaSub = StarCloudClient.instance.talk.onTalkData.listen((event) {
// event.isAudio:G711 音频;否则为视频数据,交给宿主解码器
});
final expectSub = StarCloudClient.instance.talk.onTalkExpectResp.listen((event) {
// 根据 width、height、rotate 与 videoType 重建/调整渲染器
});
final statusSub = StarCloudClient.instance.talk.onTalkStatus.listen((event) {
// 根据 TalkStatus 更新 UI 与资源生命周期
});
```
主动监控、接听和挂断:
```dart
StarCloudClient.instance.talk.requestCall(
lockPeerId: lockPeerId,
callerName: 'YourApp Monitor',
options: const TalkOptions(
preferredVideoTypes: [VideoTypeE.H264],
preferredAudioTypes: [],
),
);
StarCloudClient.instance.talk.accept(lockPeerId: incomingCall.lockPeerId);
StarCloudClient.instance.talk.hangup(lockPeerId: lockPeerId);
```
停止使用时取消订阅并释放宿主侧解码器、录音和播放器;在应用彻底退出视频对讲模块时调用 `StarCloudClient.instance.talk.dispose()`。
## 服务一览
| 服务 | 入口 | 典型能力 |
| --- | --- | --- |
| 认证 | `auth` | 初始化、SDK 云账户、WiFi 授权登录 |
| 设备 | `device` | 扫描、配对、锁列表、开关锁、重置 |
| 密码 | `password` | 查询、在线/离线密码、重置 |
| 卡片/生物识别 | `card`、`biometric` | IC 卡、指纹、人脸管理 |
| 电子钥匙 | `electricKey` | 查询、新增、编辑、冻结、删除 |
| 记录 | `record` | 查询与上报锁记录 |
| 状态/设置 | `lockState`、`lockSetting` | 锁状态、功能位读取与设置 |
| WiFi | `wifi` | WiFi 搜索、网关/锁板配网、网关状态 |
| 视频对讲 | `talk` | 注册、来电、呼叫、媒体事件、挂断 |
高级 BLE 同类请求应串行发送,避免多个相同 Reply 类型的命令同时在途导致响应匹配错误。
## 示例工程
示例位于 [example](example/README.md),当前操作顺序为:
1. 登录页注册星云应用,填写 `client_id` 与 `client_secret` 并初始化 SDK;创建测试云账户或接入业务账户。
2. 在设备扫描页扫描、直接配对门锁。
3. 在 WiFi 配网页完成“第 1 步:初始化视频对讲”,然后输入 WiFi 名称/密码并执行“第 2 步:WiFi 配网”。
4. 在视频对讲页对已联网且有 `peerId` 的锁发起监控,或处理来电。
## 故障排查
| 现象 | 优先检查 |
| --- | --- |
| `auth.init` 或 `createCloudUser` 失败 | `clientId`、`clientSecret`、授权环境地址与网络连通性 |
| 扫描不到锁 | 真机蓝牙/定位已开启,运行时权限已授予,锁处于可发现状态 |
| 配对或高级 BLE 命令超时 | 设备距离、蓝牙连接、锁的认证握手及 `StarCloudLockContext` token |
| WiFi 配网成功但无法监控 | 配网后等待锁上线,轮询锁详情确认 `isOnline == true` 且 `peerId` 非空 |
| 视频无画面 | 确认对讲已初始化、锁端协商到 H264、宿主解码器已处理 SPS/PPS/关键帧与旋转比例 |
| iOS 编译失败 | Podfile 最低版本、权限声明和 `pod install` 是否完成 |
提交支持请求时,请提供 Flutter 版本、设备型号/系统版本、操作时间、脱敏后的完整日志、锁型号和最小复现步骤。请不要提交 `clientSecret`、访问令牌、私钥或完整用户信息。
## 安全与发布
- `clientSecret`、WiFi 授权令牌、蓝牙密钥和视频对讲凭据均为敏感数据,不得写入日志或提交版本库。
- 生产环境应由业务后端管理应用凭据与用户身份,不建议在客户端内置长期密钥。
- 上线前请使用正式包名、签名、隐私政策和实际权限用途说明;按应用商店要求审核蓝牙、定位、相机与麦克风权限。
- SDK 功能与门锁固件、账号权限和已开通服务相关;请在量产前完成真实锁、弱网和异常断连测试。
## 支持
联系技术支持时请附上项目名称、SDK 版本、目标平台、问题模块和上述脱敏诊断信息。