# windows端数美设备指纹SDK接入手册

1. 适用范围#

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

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

SDK 交付产物包括:

include/SmAntiFraud.h
bin/<x86_md|x86_mt|x64_md|x64_mt>/SmAntiFraud.dll
lib/<x86_md|x86_mt|x64_md|x64_mt>/SmAntiFraud.lib
CSharp/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 为空时生效,支持 bjxjpfjny
urlstd::string依据 area 生成默认地址服务端地址;显式设置后优先于 area
extraInfostd::string空字符串业务扩展信息,最大 1024 字节
channelstd::string空字符串渠道信息
httpsbooltruetrue 使用 https://false 使用 http://
notCollectstd::vector<std::string>空数组不采集字段,例如 a9a10
smOnSuccessSmAntiSuccessCallback0成功回调
smOnErrorSmAntiErrorCallback0失败回调

默认服务地址按 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 为空时生效,支持 bjxjpfjny
urlconst char*NULL,依据 area 生成默认地址服务端地址;显式设置后优先于 area
extraInfoconst char*NULL业务扩展信息,最大 1024 字节
channelconst char*NULL渠道信息
httpsint0,表示 SDK 默认 HTTPS0=默认HTTPS1=强制HTTPS-1=强制HTTP
notCollectCsvconst char*NULL不采集字段,多个字段用英文逗号分隔
smOnSuccessSmAntiSuccessCallbackNULL成功回调
smOnErrorSmAntiErrorCallbackNULL失败回调

C API 的 urlareahttps 规则和 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 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// option.url = "https://your_server/deviceprofile/v4";
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 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// option.url = "https://your_server/deviceprofile/v4";
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# 参数类型必填默认值说明
organizationstringnull数美分配的 organization
appIdstringdefault应用 ID
publicKeystringnullRSA 公钥,支持完整 PEM,也支持只传 BEGIN/END 中间的 base64 内容
areastringbj服务区域;仅当 url 为空时生效,支持 bjxjpfjny
urlstring依据 area 生成默认地址服务端地址;显式设置后优先于 area
extraInfostringnull业务扩展信息,最大 1024 字节
channelstringnull渠道信息
httpsint,三态配置0,表示 SDK 默认 HTTPS0=默认HTTPS1=强制HTTPS-1=强制HTTP;为兼容 Native C ABI 保持 int
notCollectCsvstringnull不采集字段,逗号分隔
smOnSuccessSmSuccessCallbacknull成功回调,签名为 void Callback(string deviceId);由 SmAntiFraudBridge_win 内部持有委托引用,避免被 GC 回收
smOnErrorSmErrorCallbacknull失败回调,签名为 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 为空时按 area 生成默认地址;也可以显式设置自定义地址。
// url = "https://your_server/deviceprofile/v4",
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 大多只能在主线程调用。

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

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

4.1 回调错误码#

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

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

在线咨询