# SDK 使用说明 ## 服务地址与机器码 初始化 SDK 时传入服务端基础地址和机器码。机器码要求为 32 位字母数字字符串,SDK 会自动去除首尾空格并转换为大写。 客户端应保存同一台设备的机器码。授权票据绑定卡密和机器码,换用其他机器码会导致验签失败。 ## 接口流程 1. 调用登录或验证接口 `/api/card/verify`。 2. 保存响应中的 `licenseTicket`、`expireUnix` 和 `remainDays`。 3. 按业务周期调用 `/api/card/heartbeat` 更新在线状态。 4. 需要展示设备时调用 `/api/card/devices`。 5. 用户主动解绑时调用 `/api/card/unbind`。 ## Python 文件:`bindings/python/license_sdk.py` ```python from license_sdk import LicenseClient client = LicenseClient('https://license.example.com', '0123456789abcdef0123456789abcdef') login = client.login('CARD_KEY', '办公电脑') if login.get('ok'): print(login['licenseTicket']) heartbeat = client.heartbeat('CARD_KEY') devices = client.list_devices('CARD_KEY') client.unbind('CARD_KEY') ``` ## C# 文件:`bindings/csharp/LicenseClient.cs`,工程 `bindings/csharp/LicenseSdk.csproj`,目标 .NET 6,输出程序集名 `LicenseSdk`。 完整使用说明见 [C#/.NET DLL 使用说明](dotnet-sdk-usage.md)。 编译 DLL: ```bash cd bindings/csharp && dotnet build -c Release # 产物:bindings/csharp/bin/Release/net6.0/LicenseSdk.dll ``` 引用方式三选一: - 工程引用:在目标 .csproj 中加 ``; - 直接引用 DLL:`.../LicenseSdk.dll`; - NuGet:`dotnet pack` 生成 `LicenseSdk.5.0.0.nupkg` 后本地源安装。 SDK 提供两套等价方法:`LoginAsync` / `HeartbeatAsync` / `ListDevicesAsync` / `UnbindAsync` 返回 JSON 文档(非 2xx 抛异常);带 `ResponseAsync` 后缀的同名方法返回 `ApiResponse`(含 HTTP 状态码与原始响应体,不抛异常,便于展示服务端业务错误)。 ```csharp using System.Net.Http; using LicenseSdk; using var http = new HttpClient { BaseAddress = new Uri("https://license.example.com") }; var client = new LicenseClient(http, "0123456789abcdef0123456789abcdef"); var result = await client.LoginAsync("CARD_KEY", "办公电脑"); var heartbeat = await client.HeartbeatAsync("CARD_KEY"); // 需要读取业务错误原因时使用 ResponseAsync 系列 var resp = await client.LoginResponseAsync("CARD_KEY", "办公电脑"); if (resp.OkFlag) { /* resp.Doc 含 licenseTicket / expireUnix / remainDays */ } ``` ## Java 文件:`bindings/java/LicenseClient.java`,要求 Java 11 或更高版本。 ```java import license.sdk.LicenseClient; LicenseClient client = new LicenseClient( "https://license.example.com", "0123456789abcdef0123456789abcdef" ); LicenseClient.ApiResponse login = client.loginResponse("CARD_KEY", "办公电脑"); if (login.statusCode() == 200) { System.out.println(login.body()); } LicenseClient.ApiResponse heartbeat = client.heartbeatResponse("CARD_KEY"); ``` Java SDK 的原有方法返回 JSON 字符串;带 `Response` 后缀的方法返回 HTTP 状态码和 JSON 响应体。接入方负责解析 `ok`、`licenseTicket`、`expireUnix` 和 `remainDays`。 ## C++ 文件:`bindings/cpp/license_client.hpp` 和 `sdk-core/include/license_sdk.h`。 ```cpp #include "license_client.hpp" license_sdk::LicenseClient client("0123456789abcdef0123456789abcdef"); int status = 0; int64_t expire_unix = 0; char message[256] = {}; client.login("CARD_KEY", "办公电脑", &status, &expire_unix, message, sizeof(message)); ``` C++ 封装与底层 C ABI 当前定义了登录、设备列表和心跳方法。C ABI 的 HTTP 传输由平台绑定接入;接入前应实现 `sdk-core/src/card_flow.c` 中的传输层并传入当前设备的机器码。Python、C# 和 Java 绑定可直接调用 HTTP API。 ## 错误处理 客户端应检查响应中的 `ok` 字段和 HTTP 状态。心跳返回 `kick: true` 时,应清理本地授权状态并要求用户重新验证。常见原因包括卡密过期、卡密冻结、设备被解绑或设备被新设备顶替。