flutter_sdk/README.md
2026-09-09 16:20:05 +08:00

381 lines
14 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.

# Flutter SDK
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 版本、目标平台、问题模块和上述脱敏诊断信息。