XuqmGroup-Web/docs-site/docs/ios/license.md
XuqmGroup 06436394ed docs: fix version numbers, add license SDK docs; fix service gating reactivity
- 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>
2026-05-16 02:23:57 +08:00

4.3 KiB

iOS 授权管理License SDK

模块LicenseSDK(包含在 XuqmSDK 中)· 最低 iOS 版本iOS 16

License SDK 用于设备授权注册与验证,Android / iOS / RN / Flutter 共用同一个 AppKey,设备数量统一计算。


快速接入

1. 添加依赖

License 模块已内置于 XuqmSDK,无需额外安装包:

// Package.swift 或 Xcode → File → Add Package Dependencies
// URL: https://xuqinmin.com/xuqinmin12/XuqmGroup-iOSSDK
import XuqmSDK

2. 放置 License 文件

从租户平台下载 .xuqmlicense 加密文件,放入 App Bundle

MyApp/Resources/xuqm/license.xuqm

在 Xcode 中将该文件添加到 Target → Build Phases → Copy Bundle Resources,确保它出现在 App Bundle 中。SDK 会自动读取 Bundle.main 中的 xuqm/license.xuqm

3. 检查授权

SDK 无需手动初始化,首次调用 checkLicense() 时自动读取并解密 License 文件:

import XuqmSDK

Task {
    let result = await LicenseSDK.shared.checkLicense()
    switch result {
    case .success(let reason):
        print("授权通过:\(reason)")
    case .error(let message):
        print("授权失败:\(message)")
    }
}

API 说明

checkLicense

func checkLicense(userInfo: LicenseUserInfo? = nil) async -> LicenseResult

内部逻辑

  1. 检查本地缓存(默认 10 分钟有效期)
  2. 缓存有效 → 直接返回 .success
  3. 缓存过期或无缓存:
    • 有 Token → 调用验证接口
    • 无 Token 或验证失败 → 调用注册接口
  4. 网络异常且缓存曾成功 → 返回 .success("Offline - cached ok")
  5. 网络异常且无缓存 → 返回 .error

getStatus

func getStatus() -> LicenseStatus  // .ok / .denied / .unknown

同步查询当前状态(不发起网络请求)。

getDeviceId

func getDeviceId() -> String?

clear

func clear()

清除所有本地授权数据token、deviceId、状态


携带用户信息

注册时可携带业务用户信息,方便在租户平台进行设备管理:

let userInfo = LicenseUserInfo(
    userId: "user_001",
    name: "张三",
    email: "zhangsan@company.com"
)

let result = await LicenseSDK.shared.checkLicense(userInfo: userInfo)

设备唯一码

优先级 来源 说明
1 UIDevice.identifierForVendor 同一 App 卸载重装不变(同 Vendor
2 首次生成 UUID 存入 Keychain identifierForVendor 不可用时

数据存储

数据 存储方式 说明
deviceId KeychainSecurity framework 加密持久化
token Keychain 加密持久化
授权状态 UserDefaultsSuite: xuqm_license 非敏感
statusTime UserDefaults 缓存有效期判断

离线模式

  • 首次激活需要网络连接
  • 激活成功后,10 分钟缓存内可离线使用
  • 网络异常时,若历史缓存成功,继续返回授权通过

手动初始化(高级用法)

// 不使用 License 文件,手动指定 AppKey
LicenseSDK.shared.initialize(
    appKey: "your_app_key",
    baseUrl: "https://auth.dev.xuqinmin.com",
    deviceName: "我的 iPhone"
)

完整示例

import XuqmSDK

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .task { await checkLicense() }
        }
    }

    func checkLicense() async {
        let result = await LicenseSDK.shared.checkLicense(
            userInfo: LicenseUserInfo(userId: "user_001")
        )
        switch result {
        case .success:
            break // 授权通过,正常使用
        case .error(let msg):
            // 提示用户,限制功能入口
            print("License 验证失败: \(msg)")
        }
    }
}

常见问题

Q: checkLicense 返回 error 怎么办? 检查:

  • License 文件是否已添加到 Build Phases → Copy Bundle Resources
  • 文件路径是否为 xuqm/license.xuqm(大小写敏感)
  • 设备是否有网络连接(首次激活需要网络)
  • License 是否已过期或被管理员禁用

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