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