数美设备指纹 SDK 最低支持 Windows 7。

1. 适用范围#

本文说明 Windows Native SDK 的两类常见接入方式:

  • 普通 C++程序通过 C++ 或者 C API接入
  • Unity C# 程序通过 P/Invoke 接入

SDK 交付产物包括:

include/SmAntiFraud.h
bin/<x86_mt|x64_mt>/SmAntiFraud.dll
lib/<x86_mt|x64_mt>/SmAntiFraud.lib
CSharp/SmAntiFraudBridge_win.cs

注意:C++升级必须同时替换 .h、.lib 和 .dll;Unity升级必须同时替换 .dll 和 SmAntiFraudBridge_win.cs。不允许混用不同版本组件。

2. C++接入#

2.1 配置项目#

2.1.1 拷贝 SDK 文件#

以 x64 + MT 为例,对应 SDK 文件如下:

include/SmAntiFraud.h
lib/x64_mt/SmAntiFraud.lib
bin/x64_mt/SmAntiFraud.dll

2.1.2 配置 Visual Studio#

项目属性中配置:

C/C++ -> 常规 -> 附加包含目录:
<YourApp>/include
链接器 -> 常规 -> 附加库目录:
<YourApp>/lib
链接器 -> 输入 -> 附加依赖项:
SmAntiFraud.lib

运行时需要保证 SmAntiFraud.dll 能被程序找到。常见方式:

  • 放到 exe 同目录
  • 放到系统 PATH 中
  • 启动前把 DLL 所在目录加入 DLL 搜索路径

推荐放到 exe 同目录。

2.2 启动SDK#

2.2.1 C++ API#

调用SDK的 bool smantifraud::SmAntiFraud::Create(const smantifraud::smOption&) 方法启动SDK
Create 方法检测 smantifraud::smOption 中的必传参数是否设置,并将检测结果同步返回
若检测成功,则返回 true,SDK 会启动后台任务,异步完成设备数据采集、加密、网络请求,并缓存服务端下发的标识
若检测失败,即返回 false,需要检查参数是否配置正确

以下是 smantifraud::smOption 中具体的配置项说明:

字段参数类型必填默认值说明
organizationstd::string是空字符串数美分配的 organization
appIdstd::string否"default"应用 ID
publicKeystd::string是空字符串RSA 公钥,支持完整 PEM,也支持只传 BEGIN/END 中间的 base64 内容
areastd::string否"bj"服务区域;仅当 url 为空时生效,支持 bj、xjp、fjny
urlstd::string否依据 area 生成默认地址服务端地址;显式设置后优先于 area
confurlstd::string否依据 area 生成默认地址云配服务地址;显式设置后优先于 area
extraInfostd::string否空字符串业务扩展信息,最大 1024 字节,超出部分将被截断
channelstd::string否空字符串渠道信息
httpsbool否truetrue 使用 https://,false 使用 http://
cloudconfbool否true默认请求云配,true 代表请求
notCollectstd::vector<std::string>否空数组不采集字段,例如 a9、a10
smOnSuccessSmAntiSuccessCallback否0成功回调
smOnErrorSmAntiErrorCallback否0失败回调

默认url服务地址按 area 生成,只有 url 为空时才生效;默认使用 HTTPS:

area默认请求地址
bjhttps://fp-it.fengkongcloud.com/deviceprofile/v4
xjphttps://fp-sa-it.fengkongcloud.com/deviceprofile/v4
fjnyhttps://fp-na-it-acc.fengkongcloud.com/deviceprofile/v4

如果显式传入 url,SDK 会优先使用 url。
当 url 不带 http:// 或 https:// 前缀时,SDK 会根据 https 配置自动补全 scheme。
C++ 中设置 https=false,或 Unity 中设置 https=-1 时,area 默认地址和无 scheme 的自定义 url 都会使用 HTTP。

2.2.2 C API#

调用 SDK 的 int SmAntiFraudCreate_C(const SmAntiOption*) 方法启动 SDK。
SmAntiFraudCreate_C 会同步检测 SmAntiOption 中的必传参数是否设置。
若检测成功,则返回 SMANTI_SUCCESS,SDK 会启动后台任务,异步完成设备数据采集、加密、网络请求,并缓存服务端下发的标识。
若检测失败,则返回非 SMANTI_SUCCESS,需要检查参数是否配置正确。

使用 C API 时,调用方需要先将 SmAntiOption 清零,再填写参数:

SmAntiOption option;
memset(&option, 0, sizeof(option));

以下是 SmAntiOption 中具体的配置项说明:

字段参数类型必填默认值说明
organizationconst char*是NULL数美分配的 organization
appIdconst char*否NULL,SDK 内部按 default 处理应用 ID
publicKeyconst char*是NULLRSA 公钥,支持完整 PEM,也支持只传 BEGIN/END 中间的 base64 内容
areaconst char*否NULL,SDK 内部按 bj 处理服务区域;仅当 url 为空时生效,支持 bj、xjp、fjny
urlconst char*否NULL,依据 area 生成默认地址服务端地址;显式设置后优先于 area
confurlconst char*否NULL,依据 area 生成默认地址云配服务地址;显式设置后优先于area
extraInfoconst char*否NULL业务扩展信息,最大 1024 字节,超出部分将被截断
channelconst char*否NULL渠道信息
httpsint否0,表示 SDK 默认 HTTPS0=默认HTTPS,1=强制HTTPS,-1=强制HTTP
cloudconfint否0是否请求云配;0=默认开启,1=强制开启,-1=关闭
notCollectCsvconst char*否NULL不采集字段,多个字段用英文逗号分隔
smOnSuccessSmAntiSuccessCallback否NULL成功回调
smOnErrorSmAntiErrorCallback否NULL失败回调

C API 的 url、area、https 规则和 C++ API 一致:当 url 为空时按 area 生成默认地址;当 url 不带 http:// 或 https:// 前缀时,SDK 会根据 https 配置自动补全 scheme。设置 https=-1 时,area 默认地址和无 scheme 的自定义 url 都会使用 HTTP。

2.3 获取标识#

2.3.1 C++ API#

调用SDK的 std::string smantifraud::SmAntiFraud::GetDeviceId() 方法同步获取设备标识
该方法首先会尝试获取设备缓存的'B'开头的boxId,若获取失败,则会阻塞地采集数据并返回'D'开头,长度较长的boxdata

注意: 不要在启动SDK后立即获取标识,因为启动SDK后的异步任务需要时间,建议在启动SDK后2秒后再调用

2.3.2 C API#

调用 SDK 的 int SmAntiFraudGetDeviceId_C(char* buffer, int bufferSize) 方法同步获取设备标识。
该方法首先会尝试获取设备缓存的'B'开头的boxId,若获取失败,则会阻塞地采集数据并返回'D'开头,长度较长的boxdata。

C API 需要由调用方提供字符串缓冲区。推荐分两次调用:

  1. 第一次传入 0, 0,获取所需字符串长度。
  2. 根据返回长度分配 length + 1 字节缓冲区。
  3. 第二次传入缓冲区,读取完整字符串。

返回值说明:

返回值说明
> 0deviceId 字符串长度,不包含结尾 \0
SMANTI_ERROR_BUFFER_TOO_SMALL传入的 buffer 太小
其他负数获取失败,参考 SmAntiResult

示例:

int required = SmAntiFraudGetDeviceId_C(0, 0);
if (required > 0) {
std::vector<char> buffer(static_cast<size_t>(required) + 1);
int written = SmAntiFraudGetDeviceId_C(&buffer[0], static_cast<int>(buffer.size()));
if (written > 0) {
std::string deviceId(&buffer[0], static_cast<size_t>(written));
}
}

注意: 不要在启动 SDK 后立即获取标识,因为启动 SDK 后的异步任务需要时间,建议在启动 SDK 后 2 秒后再调用。

2.4 C++ API 接入代码示例#

#include "SmAntiFraud.h"
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
void SMANTI_CALL smOnSuccess(const char* deviceId) {
std::cout << "SmAntiFraud success: "
<< (deviceId == 0 ? "" : deviceId)
<< std::endl;
}
void SMANTI_CALL smOnError(int errorCode) {
std::cout << "SmAntiFraud error: " << errorCode << std::endl;
}
int main() {
smantifraud::smOption option;
option.organization = "your_organization"; // 必填参数
option.appId = "default";
option.publicKey = "your_public_key"; // 必填参数
option.area = "bj";
// url 和 confurl 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// option.url = "https://your_server/deviceprofile/v4";
// option.confurl = "https://your_server/v3/cloudconf";
option.extraInfo = "{\"scene\":\"login\"}";
option.notCollect.push_back("a01");
option.smOnSuccess = &smOnSuccess;
option.smOnError = &smOnError;
smantifraud::SmAntiFraud sdk;
if (!sdk.Create(option)) {
std::cout << "Create failed" << std::endl;
return 1;
}
// 2秒后再调用获取设备标识的方法
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string deviceId = sdk.GetDeviceId();
std::cout << "GetDeviceId: " << deviceId << std::endl;
return 0;
}

2.5 C API 接入代码示例#

#include "SmAntiFraud.h"
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <chrono>
#include <thread>
void SMANTI_CALL OnSuccess(const char* deviceId) {
std::cout << "success: " << (deviceId ? deviceId : "") << std::endl;
}
void SMANTI_CALL OnError(int errorCode) {
std::cout << "error: " << errorCode << std::endl;
}
std::string ReadDeviceId() {
int required = SmAntiFraudGetDeviceId_C(0, 0);
if (required <= 0) {
return std::string();
}
std::vector<char> buffer(static_cast<size_t>(required) + 1);
int written = SmAntiFraudGetDeviceId_C(&buffer[0], static_cast<int>(buffer.size()));
if (written < 0) {
return std::string();
}
return std::string(&buffer[0], static_cast<size_t>(written));
}
int main() {
SmAntiOption option;
memset(&option, 0, sizeof(option));
option.organization = "your_organization";
option.appId = "default";
option.publicKey = "your_public_key";
option.area = "bj";
// url 和 confurl 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// option.url = "https://your_server/deviceprofile/v4";
// option.confurl = "https://your_server/v3/cloudconf";
option.notCollectCsv = "a17";
option.smOnSuccess = &OnSuccess;
option.smOnError = &OnError;
int ret = SmAntiFraudCreate_C(&option);
if (ret != SMANTI_SUCCESS) {
std::cout << "SmAntiFraudCreate_C failed: " << ret << std::endl;
return 1;
}
// 2秒后再调用获取设备标识的方法
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "deviceId: " << ReadDeviceId() << std::endl;
return 0;
}

2.6 线程注意事项#

SDK 的成功和失败回调不在主线程触发,不要在回调中直接操作 UI 控件;如需更新 UI,应切回应用主线程。

3. Unity C#接入#

3.1 配置项目#

3.1.1 拷贝 C# 脚本#

将 SDK 交付包中的 SmAntiFraudBridge_win.cs 脚本复制到 Unity 工程中

Assets/Scripts/SmAntiFraudBridge_win.cs

SmAntiFraudBridge_win.cs 暴露以下接口:

类型说明
SmAntiFraudBridge_win静态封装类,内部声明并调用 Native C ABI
SmAntiFraudBridge_win.SmOption面向 Unity 的 C# 封装参数结构,脚本内部会转换为 Native C ABI 结构
SmAntiFraudBridge_win.Create初始化 SDK,并注册成功/失败回调
SmAntiFraudBridge_win.GetDeviceId获取 deviceId
SmAntiFraudBridge_win.GetSDKVersion获取 SDK 版本号

3.1.2 拷贝 Native DLL#

根据 Unity Player 架构选择对应的 DLL。推荐优先使用 MT 版本,减少客户工程对 VC++ 运行库的额外依赖。

Unity Player 架构SDK DLLUnity 目标路径
Windows x64bin/x64_mt/SmAntiFraud.dllAssets/Plugins/x64/SmAntiFraud.dll
Windows x86bin/x86_mt/SmAntiFraud.dllAssets/Plugins/x86/SmAntiFraud.dll

SmAntiFraudBridge_win.cs 中通过 DllImport("SmAntiFraud") 调用 Native 接口,DLL 文件名必须保持为 SmAntiFraud.dll。

3.2 启动SDK#

调用SDK的 int SmAntiFraudBridge_win.Create(SmAntiFraudBridge_win.SmOption) 方法启动SDK
Create 方法检测 SmAntiFraudBridge_win.SmOption 中的必传参数是否设置,并将检测结果同步返回
若检测成功,则返回 0,SDK 会启动后台任务,异步完成设备数据采集、加密、网络请求,并缓存服务端下发的标识
若检测失败,即返回非 0,需要检查参数是否配置正确

以下是 SmAntiFraudBridge_win.SmOption 中具体的配置项说明:

字段C# 参数类型必填默认值说明
organizationstring是null数美分配的 organization
appIdstring否default应用 ID
publicKeystring是nullRSA 公钥,支持完整 PEM,也支持只传 BEGIN/END 中间的 base64 内容
areastring否bj服务区域;仅当 url 为空时生效,支持 bj、xjp、fjny
urlstring否依据 area 生成默认地址服务端地址;显式设置后优先于 area
confurlstring否依据 area 生成默认地址云配服务地址;显式设置后优先于 area
extraInfostring否null业务扩展信息,最大 1024 字节,超出部分将被截断
channelstring否null渠道信息
httpsint,三态配置否0,表示 SDK 默认 HTTPS0=默认HTTPS,1=强制HTTPS,-1=强制HTTP;为兼容 Native C ABI 保持 int
cloudconfint,三态配置否0是否请求云配;0=默认开启,1=强制开启,-1=关闭
notCollectCsvstring否null不采集字段,逗号分隔
smOnSuccessSmSuccessCallback否null成功回调,签名为 void Callback(string deviceId);由 SmAntiFraudBridge_win 内部持有委托引用,避免被 GC 回收
smOnErrorSmErrorCallback否null失败回调,签名为 void Callback(int errorCode);由 SmAntiFraudBridge_win 内部持有委托引用,避免被 GC 回收

3.3 获取标识#

调用SDK的 string SmAntiFraudBridge_win.GetDeviceId() 方法同步获取设备标识
该方法首先会尝试获取设备缓存的'B'开头的boxId,若获取失败,则会阻塞地采集数据并返回'D'开头,长度较长的boxdata

注意: 不要在启动SDK后立即获取标识,因为启动SDK后的异步任务需要时间,建议在启动 SDK 的2秒后再调用

3.4 Unity 调用示例#

using System;
using System.Collections;
using UnityEngine;
public class YourSmAntiFraudBehaviour : MonoBehaviour
{
private void Start()
{
var option = new SmAntiFraudBridge_win.SmOption
{
organization = "your_organization", // 必填参数
appId = "default",
publicKey = "your_public_key", // 必填参数
area = "bj",
// url 和 confurl 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// url = "https://your_server/deviceprofile/v4",
// confurl= "https://your_server/v3/cloudconf",
extraInfo = "{\"scene\":\"unity\"}",
notCollectCsv = "a01,a02",
smOnSuccess = smOnSuccess,
smOnError = smOnError
};
int ret = SmAntiFraudBridge_win.Create(option);
Debug.Log("SmAntiFraudBridge_win.Create ret=" + ret);
if (ret == SmAntiFraudBridge_win.Success)
{
// 2秒后再调用获取设备标识的方法
StartCoroutine(GetDeviceIdAfterDelay());
}
}
private IEnumerator GetDeviceIdAfterDelay()
{
yield return new WaitForSecondsRealtime(2f);
Debug.Log("SmAntiFraudBridge_win.GetDeviceId=" + SmAntiFraudBridge_win.GetDeviceId());
}
private static void smOnSuccess(string deviceId)
{
// 保存 deviceId
}
private static void smOnError(int errorCode)
{
// errorCode错误码
}
}

3.5 Unity 线程注意事项#

SDK 的回调不在 Unity 主线程触发,而 Unity API 大多只能在主线程调用。

因此,smOnSuccess 和 smOnError 回调中不要直接操作场景对象、UI 组件、GameObject、Transform 等 Unity 对象。如果需要更新界面或游戏对象,建议在回调中只保存结果或错误码,然后在 Update()、协程或项目已有的主线程派发器中处理。

4. 返回码和错误码说明#

4.1 回调错误码#

返回码/错误码说明
1903服务端响应异常或响应内容无法解析
2001网络请求失败
2002设备信息封装或加密失败

以上错误码会通过 smOnError 失败回调返回

5. 模拟点击识别#

SDK提供API监听鼠标点击、滑动事件,用于检测模拟点击行为。

在一次开始和结束的监听期间,SDK只会采集刚开始的数条行为信息,而不会无限制的收集。
务必先 StopClickListen() 关闭上一次监听,再 StartClickListen(),才会创建新的采集周期。

注意需要在调用 Create 方法启动SDK后,才能调用以下API

5.1 C++ API#

// typedef struct SmAntiClickListenOption {
// int threshold; // 成组所需的检测条数,0 = 100; 要求此值范围 100-500
// int maxuploads; // 一次采集周期内,最大的上传次数,0 = 10
// } SmAntiClickListenOption;
//
// 返回true,代表启动成功
bool StartClickListen(const SmAntiClickListenOption* option = 0) const;
void StopClickListen() const;

5.2 C API#

// 返回0,代表启动成功
int SmAntiFraudStartClickListen_C(const SmAntiClickListenOption* option);
void SmAntiFraudStopClickListen_C(void);

5.3 C# API#

// 返回0,代表启动成功
public static int StartClickListen(SmClickListenOption option);
public static void StopClickListen();

6. 加速器识别#

SDK提供API监听一段时间内,使用如Cheat Engine实现的加速行为。

在调用 StartTimeListen  以后,SDK 内部会启动定时器,轮询检测加速情况,并进行打点上报。

注意需要在调用 Create 方法启动SDK后,才能调用以下API

6.1 C++ API#

//
// typedef struct SmAntiTimeListenOption {
// int intervalMs; // 定时器轮询间隔,0 = 1000ms;最小 1000ms
// int isEmergency; // 每次定时器检测后是否立即上报,0 = 成组上报;非0 = 立即上报
// int threshold; // 成组所需的检测条数,0 = 5条; 当isEmergency为0时生效
// } SmAntiTimeListenOption;
//
// 返回true,代表启动成功
bool StartTimeListen(const SmAntiTimeListenOption* option = 0) const;
void StopTimeListen() const;

6.2 C API#

// 返回0,代表启动成功
int SmAntiFraudStartTimeListen_C(const SmAntiTimeListenOption* option);
void SmAntiFraudStopTimeListen_C(void);

6.3 C# API#

// 返回0,代表启动成功
public static int StartTimeListen(SmTimeListenOption option);
public static void StopTimeListen();

7. 内存篡改识别#

SDK提供API监听一段时间内,使用如Cheat Engine实现的内存篡改行为。

在调用 StartMemListen  以后,SDK 内部会启动定时器,轮询检测内存情况,并进行打点上报。

注意需要在调用 Create 方法启动SDK后,才能调用以下API

7.1 C++ API#

// typedef struct SmAntiMemListenOption {
// int intervalMs; // 定时器轮询间隔,0 = 1000ms;最小 1000ms
// } SmAntiMemListenOption;
//
// 返回true,代表启动成功
bool StartMemListen(const SmAntiMemListenOption* option = 0) const;
void StopMemListen() const;

7.2 C API#

// 返回0,代表启动成功
int SmAntiFraudStartMemListen_C(const SmAntiMemListenOption* option);
void SmAntiFraudStopMemListen_C(void);

7.3 C# API#

// 返回0,代表启动成功
public static int StartMemListen(SmMemListenOption option);
public static void StopMemListen();

在线咨询