1、文档序列:
1、微信支付的文档:刷脸支付文档
2、微信支付SDK模式文档:SDK模式
2、SDK了解
提供的SDK为C动态链接库dll,入口函数原型是用C语言写的,文档里是使用C# 导入DLL声明的方法来调用的。
SDK下载后的目录如下:
3、JAVA开发中如何使用
1)下载Windows SDK ,安装并加载Dll文件
现在下载的版本是v1.28.100,目录如下:
安装目录中的exe文件,安装后会产生一个“刷脸应用”的快捷方式,在调用SDK前需要双击启用;
在下载目录,\SDK\x86\lib或者\SDK\x64\lib目录下,找到符合自己windows设备下的WxpayFaceSDK.dll文件放到C:\Windows\System32目录下,或者是放到自己的JDK安装的bin目录下;这样才可以在JAVA代码运行的时候找到并加载
以上方式二选一即可
2)查询windows设备的序列号,复制为serial.txt文件放到C盘
我的电脑上是win11,找到序列号的方式:>
打开“注册表编辑”:
“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform”,点击最后一个 SoftwareProtectionPlatform 文件夹,然后在右侧的界面中找到“BackupProductKeyDefault”文件,在文件的后方数据一栏就可以看见 Windows 11 产品密钥
3)JAVA使用JNA动态加载dll文件并实现调用
Java中加载DLL动态链接库,主要是JNI【Java官方提供的一种机制,允许Java代码调用其他语言编写的本地代码】、JNA【一种更简便的Java调用本地库的方式,无需编写额外的C/C++代码】
dll中的代码是这样的:
(1)加载dll动态链路,java中需要使用到JNA,在pom.xml中加载依赖
那我肯定使用更简便的方式,使用JNA调用DLL的步骤如下:
<!--添加JNA库-->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.5.0</version>
</dependency>
(2)定义接口:创建一个继承自 com.sun.jna.Library 的接口,描述DLL中的方法
注意:加载的“WxpayFaceSDK”名字要与复制到C:\Windows\System32目录下或JDK安装bin目录下的WxpayFaceSDK.dll文件的名称一致
描述DLL中的方法代码:
public interface WxpayFaceSDK extends Library {
WxpayFaceSDK INSTANCE = (WxpayFaceSDK) Native.load("WxpayFaceSDK", WxpayFaceSDK.class);
/**
* 调用人脸服务
* 注意:这里的方法签名需要与DLL中的C函数签名一致
* req和resp都是JSON字符串,需要转换为Pointer类型
* char * -->String; char ** -->String[]
* int -->int; int* --> IntByReference
* @param reqBuf 请求参数(JSON字符串)
* @param reqSize 请求参数长度
* @param pRespBuf 用来接收响应结果(JSON字符串)的char**指针
* @param pRespSize 用来接收响应结果长度的unsigned int*指针
* @return 如果成功返回0,失败则返回非0
*/
//int wxpayCallFaceService(String reqBuf, int reqSize, String[] pRespBuf, IntByReference pRespSize);
int wxpayCallFaceService(String reqBuf, int reqSize, long[] pRespBuf, int[] pRespSize);
/**
* char ** -->String[]
* 释放人脸服务的响应字符串,调用wxpayCallFaceService成功后务必调用此函数释放内存
* @param pRespBuf 指向响应结果(JSON字符串)的指针
*/
void wxpayReleaseResponse(String[] pRespBuf);
}
我在这里卡了很久,主要的问题就是参数类型的设置与dll中的对接不上,具体内容可以去看官网
我一开始的wxpayCallFaceService方法使用的注释掉使用String[]类型接收返回值,但返回值里一直是null值,后来想到返回值可能是一个内存地址,才改用了long[],试了很多种方法才试通。
(2)定义接口:组装出请求数据,接收数据来调用SDK。代码如下
/**
* 调用微信刷脸服务
* @param reqJson 请求数据
* @param respJson 响应数据
* @return
*/
@Override
public String callWxpayFaceService(String reqJson, List<String> respJson) {
//组装请求数据
Pointer reqPointer = new Memory(reqJson.length() + 1);
reqPointer.setString(0, reqJson);
//请求数据长度
int reqSize = reqPointer.getString(0).length();
System.out.println("-----------调用微信刷脸请求数据----------"+reqPointer.getString(0));
//接收响应
long[] pRespBuf = new long[1];
int[] respSize = new int[1];
String resStr = new String();
// 调用本地方法
int result = WxpayFaceSDK.INSTANCE.wxpayCallFaceService(reqPointer.getString(0), reqSize, pRespBuf, respSize);
if (result == 0) {
Pointer pointer = new Pointer(pRespBuf[0]);
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
resStr = new String(byteArray, StandardCharsets.UTF_8);
System.out.println("-----------调用人脸服务成功结果: " + resStr);
//释放
WxpayFaceSDK.INSTANCE.wxpayReleaseResponse(new String[2]);
} else {
Pointer pointer = new Pointer(pRespBuf[0]);
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
resStr = new String(byteArray, StandardCharsets.UTF_8);
System.err.println("-----------调用人脸服务失败: " +resStr);
}
return resStr;
}
(3)调用接口
定义了一个实体来定义请求体,名为WxFacePayReq
定义一个实体来接收详响应,名为WxFacePayResp
定义具体调用方法:使用jackson方式处理JSON数据与实体之间的转换
public WxFacePayResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws JsonProcessingException {
// 构建请求参数的JSON字符串
ObjectMapper mapper = new ObjectMapper();
String req = mapper.writeValueAsString(wxFacePayReq);
// 创建一个Pointer来接收响应
List<String> pResp= new ArrayList<>();
String result = this.callWxpayFaceService(req,pResp);
//响应结果
WxFacePayResp wxFacePayResp = mapper.readValue(result, WxFacePayResp.class);
return wxFacePayResp;
}
(4)调用测试
1、程序启动时初始化 initWxpayface
文档:初始化
官网示例:
实际调用:
2、获取数据 getWxpayfaceRawdata
文档:获取数据
官网示例:
实际调用:
extern "C" int wxpayCallFaceService(const char *reqBuf, unsigned int reqSize, char **pRespBuf, unsigned int *pRespSize);
(5)常见错误记录
我在调dll的WxpayFaceSDK中的wxpayCallFaceService方法的时候遇到很多问题;主要是
(1)报错:
Error occurred during initialization of VM
Unable to load native library: Can’t load this .dll (machine code=0x0) on a AMD 64-bit platform
原因:项目JDK版本与module版本不一致
处理方法:修改项目module的JDK版本与项目版本一致
(2)报错:Invalid memory access
原因:dll加载失败;数据类型不对应:
char * -->String; char ** -->String[]
int -->int; int* --> IntByReference
(3)不报错但是返回-1失败,却不知道原因,查了之后发现是int*类型不可以使用int,改成IntByReference后成功;改之后返回0
(4)返回值为空值,然后考虑到可能的是内存地址,把返回值改为 long[] pRespBuf, int[] pRespSize,然后将long类型的地址转换为字符串
Pointer pointer = new Pointer(pRespBuf[0]);
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
resStr = new String(byteArray, StandardCharsets.UTF_8);
以上就是我的使用过程啦,因为之前没有对接过,中间遇到了很多问题,也发现网上很少能找到能参考的文章,于是记录下来为大家提供一点点参考。
如果记录中有什么问题的话,欢迎在评论中提出来共同交流。