# Flutter SDK Flutter 智能锁接入 SDK。SDK 封装了星云账户、蓝牙扫描和配对、锁管理、凭证管理、网关 WiFi 配网、锁状态/设置,以及视频对讲信令与媒体数据事件。 > 当前交付面向 Android 和 iOS;不提供 macOS、Windows、Linux 或 Web 的桌面端支持。 ## 交付内容 `flutter_sdk` 通过固定 Git 提交依赖 `starlock_ble`、`starcloud` 和 `starchart`;`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 配网、麦克风和相机相关能力均需要在真机验证。模拟器不具备完整的蓝牙能力。 ## 安装 宿主项目需要具有读取 `minbingbing` 名下私有 Gitea 仓库的权限。`flutter_sdk` 的底层 SDK 依赖会在 `pub get` 时按固定提交自动拉取,不需要放入同级 `vendor/` 目录。 宿主 `pubspec.yaml` 的最小依赖只需要声明 `flutter_sdk`: ```yaml dependencies: flutter: sdk: flutter flutter_sdk: path: vendor/flutter_sdk ``` `flutter_sdk` 的 `pubspec.yaml` 已通过固定 Git 提交引用底层包,因此宿主执行一次依赖安装即可递归解析全部核心包: ```bash fvm flutter pub get ``` 如需将示例的 H264 FFmpeg 解码渲染带入宿主 App,额外声明: ```yaml video_decode_plugin: git: url: https://code.skychip.top/sky/video_decode_plugin.git ref: 26ce13204e017f421c6b236c0342a40c0cd120ac ``` 然后仍只需要在宿主 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 ``` - 仅使用锁管理时,麦克风、相机权限可不声明。 - Android 12 及以上需要在运行时申请 `BLUETOOTH_SCAN`、`BLUETOOTH_CONNECT`。 - 若视频对讲服务使用 `http://` 地址,Android 需要允许明文流量;生产环境建议使用 HTTPS。 ### iOS 在 `ios/Podfile` 中设置: ```ruby platform :ios, '12.0' ``` 在 `ios/Runner/Info.plist` 添加适合实际业务的用途说明: ```xml NSBluetoothAlwaysUsageDescription 用于扫描和连接智能锁。 NSBluetoothPeripheralUsageDescription 用于连接智能锁设备。 NSLocationWhenInUseUsageDescription 用于发现附近的蓝牙智能锁。 NSMicrophoneUsageDescription 用于视频对讲。 NSCameraUsageDescription 用于视频对讲和扫码功能。 ``` 完成后执行: ```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 版本、目标平台、问题模块和上述脱敏诊断信息。