- Remove docs/server/websocket.md and sidebar entry - Server API: remove Update 服务 section (only IM + Push) - Go/Python/Java SDK docs: remove Update from intro and capability tables - RN license: remove manual initialize(baseUrl) section - Flutter license: remove manual initialize(baseUrl) section - Flutter/Harmony: fix git URLs to xuqmGroup org - Harmony: add LicenseSDK to modules table and create harmony/license.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
198 行
4.3 KiB
Markdown
198 行
4.3 KiB
Markdown
# Flutter 授权管理(License SDK)
|
||
|
||
**模块**:`xuqm_flutter_license` · **依赖**:`cryptography`、`device_info_plus`、`shared_preferences`
|
||
|
||
---
|
||
|
||
## 1. 安装
|
||
|
||
在 `pubspec.yaml` 中添加:
|
||
|
||
```yaml
|
||
dependencies:
|
||
xuqm_flutter_license:
|
||
git:
|
||
url: https://xuqinmin.com/xuqmGroup/XuqmGroup-FlutterSDK.git
|
||
ref: v0.2.2
|
||
path: packages/license
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 放置 License 文件
|
||
|
||
从租户平台下载 `.xuqmlicense` 加密文件,放入 Flutter assets:
|
||
|
||
```yaml
|
||
# pubspec.yaml
|
||
flutter:
|
||
assets:
|
||
- assets/xuqm/license.xuqm
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 检查授权
|
||
|
||
```dart
|
||
import 'package:flutter/services.dart' show rootBundle;
|
||
import 'package:xuqm_flutter_license/xuqm_flutter_license.dart';
|
||
|
||
Future<void> verifyLicense() async {
|
||
// 从 assets 读取加密文件
|
||
final content = await rootBundle.loadString('assets/xuqm/license.xuqm');
|
||
|
||
// 自动解密并初始化
|
||
await initializeFromFile(content);
|
||
|
||
// 检查授权(有缓存时直接返回,否则网络验证)
|
||
final result = await checkLicense();
|
||
switch (result) {
|
||
case LicenseSuccess(reason: final r):
|
||
print('授权通过: $r');
|
||
case LicenseError(message: final m):
|
||
print('授权失败: $m');
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 携带用户信息
|
||
|
||
```dart
|
||
final result = await checkLicense(
|
||
userInfo: LicenseUserInfo(
|
||
userId: 'user_001',
|
||
name: '张三',
|
||
email: 'zhangsan@company.com',
|
||
),
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 5. API 说明
|
||
|
||
### initializeFromFile
|
||
|
||
```dart
|
||
Future<void> initializeFromFile(String encryptedContent)
|
||
```
|
||
|
||
从加密 License 文件内容自动解析 appKey 和 baseUrl 并初始化。
|
||
|
||
### checkLicense
|
||
|
||
```dart
|
||
Future<LicenseResult> checkLicense({LicenseUserInfo? userInfo})
|
||
```
|
||
|
||
返回 `LicenseSuccess(reason)` 或 `LicenseError(message)`(密封类,使用 `switch` 匹配)。
|
||
|
||
**缓存策略**:10 分钟有效期,有效期内不发起网络请求。
|
||
|
||
### getStatus
|
||
|
||
```dart
|
||
Future<LicenseStatus> getStatus() // LicenseStatus.ok / .denied / .unknown
|
||
```
|
||
|
||
### getDeviceId
|
||
|
||
```dart
|
||
Future<String?> getDeviceId()
|
||
```
|
||
|
||
### clear
|
||
|
||
```dart
|
||
Future<void> clear()
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 设备唯一码
|
||
|
||
| 平台 | 来源 | 说明 |
|
||
|------|------|------|
|
||
| Android | `androidInfo.id` | `Settings.Secure.ANDROID_ID` |
|
||
| iOS | `iosInfo.identifierForVendor` | 同 Vendor 下卸载重装不变 |
|
||
| 其他 | 生成 UUID 存入 SharedPreferences | fallback |
|
||
|
||
---
|
||
|
||
## 7. 数据存储
|
||
|
||
| 数据 | 存储方式 | 说明 |
|
||
|------|----------|------|
|
||
| deviceId | SharedPreferences | 持久化 |
|
||
| token | SharedPreferences | 持久化 |
|
||
| 授权状态 | SharedPreferences | 非敏感,持久化 |
|
||
| statusTime | SharedPreferences | 缓存有效期判断 |
|
||
|
||
---
|
||
|
||
## 8. 离线模式
|
||
|
||
- 首次激活需要网络连接
|
||
- 激活后 10 分钟缓存内可离线使用
|
||
- 网络异常时,若历史缓存成功,继续返回 `LicenseSuccess`
|
||
|
||
---
|
||
|
||
## 9. 完整示例
|
||
|
||
```dart
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:xuqm_flutter_sdk/xuqm_flutter_sdk.dart';
|
||
import 'package:xuqm_flutter_license/xuqm_license.dart' as license;
|
||
|
||
void main() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
await XuqmSDK.initialize(XuqmInitOptions(appKey: 'your_app_key'));
|
||
|
||
// 初始化 License
|
||
final content = await rootBundle.loadString('assets/xuqm/license.xuqm');
|
||
await license.initializeFromFile(content);
|
||
|
||
runApp(const MyApp());
|
||
}
|
||
|
||
class MyApp extends StatelessWidget {
|
||
const MyApp({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return MaterialApp(
|
||
home: FutureBuilder(
|
||
future: license.checkLicense(
|
||
userInfo: license.LicenseUserInfo(userId: 'user_001'),
|
||
),
|
||
builder: (context, snapshot) {
|
||
if (!snapshot.hasData) return const CircularProgressIndicator();
|
||
final result = snapshot.data!;
|
||
if (result is license.LicenseError) {
|
||
return Scaffold(
|
||
body: Center(child: Text('授权失败: ${result.message}')),
|
||
);
|
||
}
|
||
return const HomePage();
|
||
},
|
||
),
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 常见问题
|
||
|
||
**Q: 提示 `Invalid license file format`?**
|
||
检查 License 文件是否完整,以及是否已在 `pubspec.yaml` 的 `flutter.assets` 中声明。
|
||
|
||
**Q: 不同平台可以用同一个 License 吗?**
|
||
可以,所有平台共用同一个 AppKey,设备数量统一计算。
|