跳到正文
LICENTIVO / INTEGRATION

C 软件授权 SDK:CMake 接入教程

为 C11 应用接入授权激活与功能权限检查。通过完整 CMake 示例学习设备凭证恢复和授权拒绝处理。

C11更新日期

1. 准备产品与许可证

为原生 C11 应用选择 C SDK,激活客户授权,并在调用业务回调前检查功能权限。先使用设备绑定授权和不计量的导出功能,基本流程跑通后再添加用量计数。

设备额度按当前激活设备计算,释放后返还;普通授权离线仍占用,浮动授权租约到期后自动返还。

  1. 在控制台“产品”复制产品 ID,点击同一产品的“签名公钥”,将每一组密钥 ID、公钥填进初始化代码,替换 YOUR_PRODUCT_ID、YOUR_KEY_ID 和 YOUR_PUBLIC_KEY。快速接入也可以直接复制已填好的代码。无需配置文件;SDK 默认连接 https://www.licentivo.com。
  2. 在「快速接入」创建或选择产品,在策略中启用名为 export 的功能,并准备测试许可证。

2. 安装 SDK

先安装 CMake 3.18 或更高版本。Windows x64 使用 Visual Studio 2022 C++ Build Tools 与匹配的 MSVC SDK 包,并指定 -G "Visual Studio 17 2022" -A x64;Linux x64 使用 C11/C++17 编译器。将 SDK_PREFIX 替换为安装器输出的 CMake 前缀路径。 将示例源码保存为 app.c,并将下方 CMakeLists.txt 保存到同一目录。

安装与编译器、架构一致的共享版 libcurl 开发包。Windows MSVC x64 用户需将 CURL_DIR 替换为包含 CURLConfig.cmake 的目录,本地运行时把 curl 的 bin 目录加入 PATH,发布应用时附带所需 DLL;Linux 用户安装发行版提供的共享版 libcurl 开发包。

Windows · PowerShell
& ([scriptblock]::Create((Invoke-WebRequest 'https://www.licentivo.com/assets/sdk/releases/v0.11.6/install.ps1').Content)) -Language c -Toolchain msvc
Linux · Bash
curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' 'https://www.licentivo.com/assets/sdk/releases/v0.11.6/install.sh' | bash -s -- c
CMake · CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(licensed_app LANGUAGES C)
find_package(Licentivo 0.11.6 REQUIRED)
add_executable(licensed_app app.c)
target_link_libraries(licensed_app PRIVATE Licentivo::C)
set_target_properties(licensed_app PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON)
Windows x64 · PowerShell · MSVC
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_PREFIX_PATH="SDK_PREFIX" -DCURL_DIR="CURL_DIR"
if ($LASTEXITCODE -ne 0) { throw 'CMake configure failed. Check the SDK prefix and matching libcurl development package.' }
cmake --build build --config Release --target licensed_app
if ($LASTEXITCODE -ne 0) { throw 'Build failed.' }
Linux x64 · Bash
set -e
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="SDK_PREFIX"
cmake --build build --target licensed_app

3. 保护一次实际导出

将 SDK 初始化接到自己软件的启动或激活入口,从激活窗口读取客户授权码,传入自己的产品 ID、受信公钥并保持客户端存活。把 ln_run_feature 放在真实业务入口,将导出示例函数替换成自己的实际功能。

C11 · app.c
#include "licentivo.h"
#include <stdio.h>
#include <stdlib.h>

/* BEGIN LICENTIVO PRODUCT */
/* Copy Product ID and all key ID/public key pairs from Console > Products > Signing public keys. */
static const char *PRODUCT_ID = "YOUR_PRODUCT_ID";
static const char *TRUSTED_KEYS_JSON = "{\"YOUR_KEY_ID\":\"YOUR_PUBLIC_KEY\"}";
/* END LICENTIVO PRODUCT */

static const char *setting(const char *name, const char *fallback) {
    const char *value = getenv(name);
    return value && value[0] ? value : fallback;
}

static int export_report(void *context) {
    const char *path = (const char *)context;
    /* Replace this write with your existing, non-metered export operation. */
    FILE *file = fopen(path, "w");
    if (!file) { perror("Export write failed"); return 0; }
    int wrote = fputs("A report generated by the licensed application.\n", file) >= 0;
    int closed = fclose(file) == 0;
    return wrote && closed;
}

int main(void) {
    /* Keep the handle to report startup errors. A GUI supplies the activation input. */
    ln_client *client = ln_init_product(PRODUCT_ID, TRUSTED_KEYS_JSON, setting("LICENTIVO_LICENSE_KEY", ""));
    if (!client) {
        fputs("Startup failed: check the product ID and public keys and supply a license key for first activation.\n", stderr);
        return 2;
    }
    if (!ln_start(client)) {
        fprintf(stderr, "Startup failed: %s\n", ln_last_error(client));
        ln_destroy(client);
        return 2;
    }
    const char *feature = setting("LICENTIVO_FEATURE", "export");
    const char *path = setting("LICENTIVO_OUTPUT", "licensed-report.txt");
    int ok = setting("LICENTIVO_METERED", "")[0] == '1'
        ? ln_run_metered_feature(client, feature, 1, setting("LICENTIVO_OPERATION_ID", ""), export_report, (void *)path)
        : ln_run_feature(client, feature, export_report, (void *)path);
    if (!ok) {
        char *status = ln_feature_status(client, feature);
        fprintf(stderr, "Export denied or failed: %s; %s\n", status ? status : "status unavailable", ln_last_error(client));
        ln_free_string(status);
    }
    if (ok) printf("License OK: %s is available\nExport completed: %s\n", feature, path);
    ln_destroy(client); /* Real app: destroy on shutdown; no Deactivate on normal exit. */
    return ok ? 0 : 2;
}

4. 在应用退出时关闭客户端

本命令行示例执行一次操作后退出。接入桌面应用时,在启动时创建一个客户端,在导出按钮或命令中调用功能回调,直到应用退出才关闭客户端。

首次激活后,后续启动可将 LICENTIVO_LICENSE_KEY 留空,在相同用户及缓存位置恢复私有设备凭据。凭据保存在用户应用数据目录,不随安装包分发。关闭客户端会停止心跳并归还浮动席位;普通退出不应注销设备绑定。

只有策略允许、签名授权仍有效时才能离线使用。许可证过期或功能被拒绝时继续阻止业务操作;功能次数计量需要联网。

保留 ln_client 句柄直到退出。ln_start 执行启动验证,受保护业务交给 ln_run_feature 或计次接口调用。业务回调成功返回 1,失败返回 0;状态字符串用 ln_free_string 释放,应用退出时调用 ln_destroy。

5. 运行并核对结果

  1. 使用允许 export 的有效许可证运行,确认生成 licensed-report.txt。
  2. 清空 LICENTIVO_LICENSE_KEY,以相同用户再次运行,确认可恢复已保存的设备凭据。
  3. 把 LICENTIVO_FEATURE 改为许可证没有的功能,并将 LICENTIVO_OUTPUT 改为新文件名。程序应提示拒绝,且不生成新文件。
  4. 仅在策略允许且签名授权未到期时测试离线重启。后台刷新报错后,也不能绕过失败的功能检查。
Windows · PowerShell
$env:LICENTIVO_LICENSE_KEY = 'YOUR_TEST_LICENSE_KEY'
./build/Release/licensed_app.exe
Remove-Item Env:LICENTIVO_LICENSE_KEY
./build/Release/licensed_app.exe
Linux x64 · Bash
LICENTIVO_LICENSE_KEY=YOUR_TEST_LICENSE_KEY ./build/licensed_app
unset LICENTIVO_LICENSE_KEY
./build/licensed_app

常见接入问题

检查产品 ID、每组密钥 ID 和公钥、客户输入的授权码。公钥属于产品;客户许可证和本机凭证分别管理。开发测试授权码和厂商管理 API Key 不进入客户安装包。

功能被拒绝、设备数已满或许可证过期:在控制台核对许可证及策略,并向客户显示 SDK 错误。授权失败时不能调用导出函数。

普通功能接口只检查权限;计次接口负责预留和结算已配置的用量。每项真实业务使用独立且稳定的操作编号;中断恢复前先核对持久化业务结果。

CMake 找不到 Licentivo 时,用安装器输出的 CMake prefix 替换配置命令中的 SDK_PREFIX。编译器、架构和 libcurl 必须与原生包匹配。