XuqmGroup-Web/docs-site/docs/flutter/license.md
XuqmGroup e912a5e65e docs: remove WebSocket doc, strip Update from server SDKs, add Harmony license
- 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>
2026-05-16 11:56:40 +08:00

4.3 KiB

Flutter 授权管理License SDK

模块xuqm_flutter_license · 依赖cryptographydevice_info_plusshared_preferences


1. 安装

pubspec.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

# pubspec.yaml
flutter:
  assets:
    - assets/xuqm/license.xuqm

3. 检查授权

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. 携带用户信息

final result = await checkLicense(
  userInfo: LicenseUserInfo(
    userId: 'user_001',
    name: '张三',
    email: 'zhangsan@company.com',
  ),
);

5. API 说明

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.yamlflutter.assets 中声明。

Q: 不同平台可以用同一个 License 吗? 可以,所有平台共用同一个 AppKey,设备数量统一计算。