C SDK 快速接入

华网科技 ∙ hwwlyz.com2026/06/02

华网网络验证提供了官方的 C 语言 SDK,纯 C11 实现,无第三方依赖,方便嵌入式/IoT/桌面应用开发者接入。

接入须知

获取方式

下载地址:https://wwaqe.lanzouq.com/b00odxkaheopen in new window 密码:b0b5
或者加群839808671在群文件下载SDK,有问题也可在此群交流。

鸣谢

作者:wiki 提供基础验证包源码,由官方调整优化发布

开发环境

平台编译器构建工具验证状态
macOSApple Clang (Xcode)CMake + Ninja/Make✅ 通过
WindowsMinGW-w64 GCC 14.2CMake + MinGW Makefiles✅ 通过
LinuxGCC / ClangCMake + Make✅ 理论兼容

前置工具

获取方式

hwsdk.hhwsdk.c 放入工程,搭配 CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(my_app C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

add_library(hwsdk STATIC hwsdk.c)
target_include_directories(hwsdk PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
find_package(Threads REQUIRED)
target_link_libraries(hwsdk PUBLIC Threads::Threads)
if(WIN32)
  target_link_libraries(hwsdk PUBLIC ws2_32)
endif()

add_executable(my_app main.c)
target_link_libraries(my_app PRIVATE hwsdk)

构建步骤

# macOS
cmake -S . -B build
cmake --build build

# Windows (MinGW)
cmake -S . -B build -G "MinGW Makefiles"
cmake --build build

最小示例

#include "hwsdk.h"
#include <stdio.h>

#ifdef _WIN32
#include <windows.h>
#endif

// 心跳异常回调
static void on_hb_failed(hw_sdk* sdk, const hw_resp* r) {
  printf("[HB FAILED] code=%d message=%s\n", r->code, r->message);
  if (sdk->login_type == HW_LOGIN_CARD) {
    hw_resp lr;
    hw_card_login(sdk, &lr);
    printf("[RELOGIN] code=%d message=%s\n", lr.code, lr.message);
  }
}

int main(void) {
#ifdef _WIN32
  SetConsoleOutputCP(CP_UTF8);  // Windows 控制台输出中文
#endif

  if (!hw_net_init()) {
    printf("网络初始化失败\n");
    return 1;
  }

  // 初始化 SDK
  hw_sdk sdk;
  hw_sdk_init(&sdk, "你的AppKey", "你的AppSecret");

  hw_sdk_set_debug(&sdk, 0);            // 调试开关,1=开启
  hw_sdk_set_retry(&sdk, 9);            // 连接失败重试次数
  hw_sdk_set_heartbeat_gap(&sdk, 120);  // 心跳间隔(秒)
  hw_sdk_set_auto_heartbeat(&sdk, 1);   // 开启自动心跳
  hw_sdk_set_heartbeat_callback(&sdk, on_hb_failed);

  // 设置卡密并登录
  hw_sdk_set_device_id(&sdk, "设备唯一标识");
  hw_sdk_set_card(&sdk, "你的卡密");

  hw_resp r;
  hw_card_login(&sdk, &r);

  printf("[LOGIN] code=%d message=%s\n", r.code, r.message);
  if (r.code != 0) {
    hw_net_cleanup();
    return 1;
  }

  printf("卡密类型: %s\n", r.cardType);
  printf("到期时间: %s\n", r.expires);
  printf("Token:    %s\n", r.token);

  // 启动自动心跳(登录成功后调用)
  hw_start_heartbeat(&sdk);

  // ========== 你的业务代码 ==========
  // ...

  // =================================

  // 退出时停止心跳并清理
  hw_stop_heartbeat(&sdk);
  hw_net_cleanup();
  return 0;
}

数据结构

hw_resp(响应体)

typedef struct {
  int code;              // 返回码,0=成功
  char message[256];     // 错误信息
  char sign[64];         // 响应签名

  char token[128];       // 登录令牌
  char expires[64];      // 过期时间(格式化)
  long long expiresTs;    // 过期时间戳(秒)
  char config[256];      // 配置内容
  long long serverTime;   // 服务器时间戳(秒)
  char cardType[64];     // 卡密类型,如"年卡""月卡"

  char notice[512];      // 软件公告
  char value[256];       // 远程变量值
  char result[256];      // 远程函数返回值
} hw_resp;

hw_login_type(登录类型)

typedef enum {
  HW_LOGIN_NONE  = 0,  // 未登录
  HW_LOGIN_CARD  = 1,  // 卡密登录
  HW_LOGIN_USER  = 2,  // 用户登录
  HW_LOGIN_TRIAL = 3,  // 试用登录
} hw_login_type;

初始化

初始化 SDK

void hw_sdk_init(hw_sdk* s, const char* appKey, const char* appSecret);

初始化卡密

void hw_sdk_set_card(hw_sdk* s, const char* card);
参数必传类型说明
cardconst char*卡密(长度不超过45位)

初始化用户账号

void hw_sdk_set_user(hw_sdk* s, const char* username, const char* password);
参数必传类型说明
usernameconst char*用户名(1-20位)
passwordconst char*密码(6-30位)

初始化设备标识

void hw_sdk_set_device_id(hw_sdk* s, const char* deviceId);
参数必传类型说明
deviceIdconst char*设备唯一标识码

初始化心跳回调

void hw_sdk_set_heartbeat_callback(hw_sdk* s, hw_heartbeat_failed_cb cb);

回调函数签名:void (*hw_heartbeat_failed_cb)(hw_sdk* sdk, const hw_resp* r);
当心跳返回 code ≠ 0 或网络请求失败时触发。

卡密

卡密登录

登录成功后将自动把 login_type 设为 HW_LOGIN_CARD,token 写入 sdk.token

int hw_card_login(hw_sdk* s, hw_resp* out);

// 用前需设置
hw_sdk_set_device_id(&sdk, "设备ID");
hw_sdk_set_card(&sdk, "卡密");
返回值说明
1请求完成(具体结果看 out->code,0=成功)
0网络传输失败
// 示例
hw_resp r;
hw_card_login(&sdk, &r);
if (r.code == 0) {
  printf("登录成功: cardType=%s expires=%s\n", r.cardType, r.expires);
  hw_start_heartbeat(&sdk);  // 启动自动心跳
} else {
  printf("登录失败: %s\n", r.message);
}

卡密心跳

int hw_card_heartbeat(hw_sdk* s, hw_resp* out);

一般无需手动调用,hw_start_heartbeat 会按 heartbeat_gap_sec 间隔自动发送。

卡密退出登录

int hw_card_logout(hw_sdk* s, hw_resp* out);

// 示例
hw_resp r;
hw_card_logout(&sdk, &r);
printf("退出 code=%d message=%s\n", r.code, r.message);
hw_stop_heartbeat(&sdk);  // 停止心跳线程

卡密解绑设备

需先在开发者后台配置"开启设备绑定且可解除绑定"

int hw_card_unbind_device(hw_sdk* s, hw_resp* out);

// 示例(登录后调用)
hw_resp r;
hw_card_unbind_device(&sdk, &r);
printf("解绑 code=%d message=%s\n", r.code, r.message);

卡密设置解绑密码

用于设备丢失时通过密码解绑

int hw_card_set_unbind_password(hw_sdk* s, const char* password, hw_resp* out);
参数必传类型说明
passwordconst char*解绑密码(6-10位)
// 示例
hw_resp r;
hw_card_set_unbind_password(&sdk, "MyPwd123", &r);
printf("设置解绑密码 code=%d message=%s\n", r.code, r.message);

卡密通过密码解绑设备

int hw_card_unbind_by_password(hw_sdk* s, const char* password, hw_resp* out);
参数必传类型说明
passwordconst char*解绑密码(6-10位)
// 示例(无需登录即可调用)
hw_sdk_init(&sdk, "appKey", "appSecret");
hw_sdk_set_card(&sdk, "被解绑的卡密");

hw_resp r;
hw_card_unbind_by_password(&sdk, "MyPwd123", &r);
printf("密码解绑 code=%d message=%s\n", r.code, r.message);

卡密充值(以卡充卡)

int hw_card_recharge(hw_sdk* s, const char* useCard, hw_resp* out);
参数必传类型说明
useCardconst char*充值使用的卡密(不超过45位)
// 示例(登录后调用)
hw_resp r;
hw_card_recharge(&sdk, "充值卡密", &r);
printf("充值 code=%d message=%s\n", r.code, r.message);

用户

用户登录

登录成功后将自动把 login_type 设为 HW_LOGIN_USER,token 写入 sdk.token

int hw_user_login(hw_sdk* s, hw_resp* out);

// 用前需设置
hw_sdk_set_user(&sdk, "用户名", "密码");
// 示例
hw_resp r;
hw_user_login(&sdk, &r);
if (r.code == 0) {
  printf("登录成功: token=%s expires=%s\n", r.token, r.expires);
  hw_start_heartbeat(&sdk);
}

用户心跳

int hw_user_heartbeat(hw_sdk* s, hw_resp* out);

一般无需手动调用,自动心跳线程会根据 login_type 自动选择。

用户退出登录

int hw_user_logout(hw_sdk* s, hw_resp* out);

用户注册(通过卡密)

int hw_user_register(hw_sdk* s, const char* card, const char* password, hw_resp* out);
参数必传类型说明
cardconst char*注册使用的卡密(不超过45位)
passwordconst char*用户密码(6-30位)
// 示例:先设置用户名,再调用注册
hw_sdk_set_user(&sdk, "新用户名", "");

hw_resp r;
hw_user_register(&sdk, "注册卡密", "用户密码", &r);
printf("注册 code=%d message=%s\n", r.code, r.message);

用户修改密码

int hw_user_set_password(hw_sdk* s, const char* oldPassword,
                         const char* newPassword, hw_resp* out);
参数必传类型说明
oldPasswordconst char*当前密码
newPasswordconst char*新密码(6-30位)
// 示例(登录后调用)
hw_resp r;
hw_user_set_password(&sdk, "旧密码", "新密码", &r);
printf("改密 code=%d message=%s\n", r.code, r.message);

用户充值(通过卡密)

int hw_user_recharge(hw_sdk* s, const char* card, hw_resp* out);
参数必传类型说明
cardconst char*充值使用的卡密(不超过45位)
// 示例(登录后调用)
hw_resp r;
hw_user_recharge(&sdk, "充值卡密", &r);
printf("充值 code=%d message=%s\n", r.code, r.message);

试用

试用登录

登录成功后将自动把 login_type 设为 HW_LOGIN_TRIAL

int hw_trial_login(hw_sdk* s, hw_resp* out);

// 用前需设置
hw_sdk_set_device_id(&sdk, "设备ID");
// 示例
hw_resp r;
hw_trial_login(&sdk, &r);
if (r.code == 0) {
  printf("试用登录成功 expires=%s expiresTs=%lld\n", r.expires, r.expiresTs);
  hw_start_heartbeat(&sdk);
}

试用心跳

int hw_trial_heartbeat(hw_sdk* s, hw_resp* out);

一般无需手动调用,自动心跳线程会根据 login_type 自动选择。

配置

获取卡密配置

int hw_card_get_config(hw_sdk* s, hw_resp* out);

// 用前需设置
hw_sdk_set_card(&sdk, "卡密");
// 示例
hw_resp r;
hw_card_get_config(&sdk, &r);
printf("卡密配置: code=%d config=%s\n", r.code, r.config);

设置卡密配置

int hw_card_set_config(hw_sdk* s, const char* config, hw_resp* out);
参数必传类型说明
configconst char*配置内容(不超过512位)
// 示例
hw_resp r;
hw_card_set_config(&sdk, "我的自定义配置", &r);
printf("设置配置 code=%d\n", r.code);

获取用户配置

int hw_user_get_config(hw_sdk* s, hw_resp* out);

// 用前需设置
hw_sdk_set_user(&sdk, "用户名", "密码");

设置用户配置

int hw_user_set_config(hw_sdk* s, const char* config, hw_resp* out);
// 示例
hw_resp r;
hw_user_set_config(&sdk, "用户专属配置", &r);
printf("设置用户配置 code=%d\n", r.code);

软件

获取软件配置

int hw_software_get_config(hw_sdk* s, hw_resp* out);

// 示例
hw_resp r;
hw_software_get_config(&sdk, &r);
printf("软件配置: code=%d config=%s\n", r.code, r.config);

获取软件公告

int hw_software_get_notice(hw_sdk* s, hw_resp* out);

// 示例
hw_resp r;
hw_software_get_notice(&sdk, &r);
printf("软件公告: code=%d notice=%s\n", r.code, r.notice);

获取软件最新版本

该接口不参与 sign 计算

int hw_software_get_version(hw_sdk* s, const char* version, hw_resp* out);
参数必传类型说明
versionconst char*当前本地版本号
// 示例
hw_resp r;
hw_software_get_version(&sdk, "1.0.0", &r);
printf("版本检查: code=%d\n", r.code);
// code=0 表示有新版本,code≠0 已是最新

远程变量

创建远程变量

int hw_senior_add_var(hw_sdk* s, const char* key,
                      const char* value, hw_resp* out);
参数必传类型说明
keyconst char*变量名(不超过64位)
valueconst char*变量值(不超过256位)
// 示例
hw_resp r;
hw_senior_add_var(&sdk, "my_key", "hello", &r);
printf("创建变量 code=%d message=%s\n", r.code, r.message);

获取远程变量

int hw_senior_get_var(hw_sdk* s, const char* key, hw_resp* out);
// 示例
hw_resp r;
hw_senior_get_var(&sdk, "my_key", &r);
printf("获取变量: code=%d value=%s\n", r.code, r.value);

修改远程变量

int hw_senior_set_var(hw_sdk* s, const char* key,
                      const char* value, hw_resp* out);
// 示例
hw_resp r;
hw_senior_set_var(&sdk, "my_key", "updated_value", &r);
printf("修改变量 code=%d\n", r.code);

删除远程变量

int hw_senior_del_var(hw_sdk* s, const char* key, hw_resp* out);
// 示例
hw_resp r;
hw_senior_del_var(&sdk, "my_key", &r);
printf("删除变量 code=%d\n", r.code);

远程函数

调用远程函数

int hw_senior_call_fun(hw_sdk* s, const char* funName,
                       const char* params, hw_resp* out);
参数必传类型说明
funNameconst char*远程函数名(不超过64位)
paramsconst char*JSON 列表字符串,如 "[10, 20]"(不超过256位)

示例:假设开发后台定义了一个远程函数 add

function add(a, b) {
  return a + b;
}
// C 端调用
hw_resp r;
hw_senior_call_fun(&sdk, "add", "[10, 20]", &r);
if (r.code == 0) {
  printf("add(10,20) = %s\n", r.result);  // 输出: add(10,20) = 30
} else {
  printf("调用失败: %s\n", r.message);
}

心跳管理

启动自动心跳

登录成功后调用,SDK 根据 login_type 自动选择卡密/用户/试用心跳接口。重复调用会自动停止旧线程再启新线程。

void hw_start_heartbeat(hw_sdk* s);

停止自动心跳

void hw_stop_heartbeat(hw_sdk* s);

心跳配置

// 设置心跳间隔(秒),默认 120,请勿低于 60
hw_sdk_set_heartbeat_gap(&sdk, 120);

// 开启/关闭自动心跳,默认开启
hw_sdk_set_auto_heartbeat(&sdk, 1);

// 心跳异常回调
hw_sdk_set_heartbeat_callback(&sdk, on_hb_failed);

其他配置

调试开关

hw_sdk_set_debug(&sdk, 1);  // 开启后输出每次请求的详细日志到 stderr
hw_sdk_set_debug(&sdk, 0);  // 关闭

重试次数

连接失败时的重试次数(Fibonacci 间隔),默认 9 次。

hw_sdk_set_retry(&sdk, 9);

自定义服务器地址

const char* hosts[] = {"api.hwwlyz.com", "api3.hwwlyz.com", "api6.hwwlyz.com"};
hw_sdk_set_hosts(&sdk, hosts, 3);

网络初始化与清理

int  hw_net_init(void);     // 程序启动时调用,Windows 上初始化 WinSock
void hw_net_cleanup(void);   // 程序退出时调用

返回码对照表

返回码说明
0成功
-1SDK 内部:连接服务器失败
-2SDK 内部:响应签名校验失败
-4SDK 内部:响应时间超时
51参数错误
10101签名已过期(60s 有效且一次性)
10102时间戳大于服务器时间
10103appKey/appSecret 不匹配
10104无效签名
10105账户欠费停用
10201软件不存在
10202卡密不可用
10203卡密已冻结
10204卡密已过期
10205卡密已被使用
10206超过多开上限
10207登录状态已失效
10208超出可绑定设备上限
10209解绑密码不正确
10301账号已存在
10302用户密码错误
10303用户已到期
10401远程变量不存在
10402远程变量不支持 API 修改
10403远程变量名已存在
10501远程函数不存在
10601已是最新版本
10701软件未开启试用
10702本次试用已到期
10703试用已到期(一次性试用)
10704本周期试用已到期(间隔试用)
10705请先登录
10706设备正在试用,请勿重复登录
Last Updated 2026/6/2 17:40:41
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.14.7