- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10 - iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0" - RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table - Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables - Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license - tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change - tenant-platform: add requestActivation API endpoint - tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.5 KiB
4.5 KiB
Flutter 授权管理(License SDK)
模块:xuqm_flutter_license · 依赖:cryptography、device_info_plus、shared_preferences
1. 安装
在 pubspec.yaml 中添加:
dependencies:
xuqm_flutter_license:
git:
url: https://xuqinmin.com/xuqinmin12/XuqmGroup-FlutterSDK.git
ref: v0.2.2
path: packages/license
2. 放置 License 文件
从租户平台下载 .xuqmlicense 加密文件,放入 Flutter assets:
# pubspec.yaml
flutter:
assets:
- assets/xuqm/license.xuqm
3. 检查授权
import 'package:flutter/services.dart' show rootBundle;
import 'package:xuqm_flutter_license/xuqm_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. 携带用户信息
final result = await checkLicense(
userInfo: LicenseUserInfo(
userId: 'user_001',
name: '张三',
email: 'zhangsan@company.com',
),
);
5. API 说明
initialize
void initialize(String appKey, {String? baseUrl, String? deviceName})
手动初始化,适用于不使用 License 文件的场景。
initializeFromFile
Future<void> initializeFromFile(String encryptedContent)
从加密 License 文件内容自动解析 appKey 和 baseUrl 并初始化。
checkLicense
Future<LicenseResult> checkLicense({LicenseUserInfo? userInfo})
返回 LicenseSuccess(reason) 或 LicenseError(message)(密封类,使用 switch 匹配)。
缓存策略:10 分钟有效期,有效期内不发起网络请求。
getStatus
Future<LicenseStatus> getStatus() // LicenseStatus.ok / .denied / .unknown
getDeviceId
Future<String?> getDeviceId()
clear
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. 完整示例
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,设备数量统一计算。