Jni开发(一)编写Jni头文件

Jni开发(一)编写Jni头文件

之前简单的写过一篇文章《Android Studio-Jni开发》,介绍的是如何在AndroidStudio上进行Jni开发,使用CMakeLists进行配置并生成so。本次介绍如何使用Makefile编译C代码生成so,并在Linux系统上运行测试代码。

生成Jni头文件

生成Jni头文件,如果方法较多的话,我使用的AndroidStudio进行快速生成。

一、创建native方法

创建SDFAPI.java 类文件:

//-----------------------------设备管理类---------------------------------------
    public native int OpenDevice(long[] phDeviceHandle);

    public native int OpenDeviceByIndex(int devIndex, long[] phDeviceHandle);

    public native int CloseDevice(long hDeviceHandle);

    public native int OpenSession(long hDeviceHandle, long[] phSessionHandle);

    public native int CloseSession(long hSessionHandle);

    public native int GetDeviceInfo(long hSessionHandle, DeviceInfo pstDeviceInfo);

    public native int GenerateRandom(long hSessionHandle, int uiLength, byte[] pucRandom);

    public native int GetPrivateKeyAccessRight(long hSessionHandle, int uiKeyIndex, byte[] pucPassword, int uiPwdLength);

    public native int ReleasePrivateKeyAccessRight(long hSessionHandle, int uiKeyIndex);

二、 实现native方法

如图,未实现的native方法,方法名称会变红,按alt+enter自动生成jni文件sdfapi.c。
测试图
spiapi.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "sdfapi.h"
#include "tool.h"

JNIEXPORT jint JNICALL
Java_com_dream_test_SDFAPI_OpenDevice(JNIEnv *env, jobject thiz, jlongArray ph_device_handle) {
    int ret;
    jlong dev[] = {0};

    ret = SDF_OpenDevice((void **) dev);// 所依赖库的头文件
    if (!ret) {
        (*env)->SetLongArrayRegion(env, ph_device_handle, 0, 1, dev);
    }

    return c2j_errCode(ret);// 返回错误码
}

JNIEXPORT jint JNICALL
Java_com_dream_test_SDFAPI_GetDeviceInfo(JNIEnv *env, jobject thiz, jlong h_session_handle, jobject pst_device_info) {
    int ret;
    DEVICEINFO devi;// 实体类对应的C结构体

    jclass cls;
    const char *csi = "com/dream/test/DeviceInfo";// 实体类包名

    if (!pst_device_info) {// 判断输入参数不为空
        //throw_null_pointer_exception(env, "pst_device_info");// 抛出异常信息
        goto err1;
    }
    memset(&devi, 0x0, sizeof(devi));
    ret = SDF_GetDeviceInfo((void *) h_session_handle, &devi);
    if (!ret) {
        cls = (*env)->FindClass(env, csi);
        if (!cls) {
            //throw_class_not_found_exception(env, csi);
            goto err0;
        }
		// 结构体 devi 中数据 赋值给 java实体类 pst_device_info 。下列自定义转换方法写在tool.c中以便引用
        ret = set_byte_array(env, cls, csi, pst_device_info, "setIssuerName", (jbyte *) devi.IssuerName, sizeof(devi.IssuerName));
        if (ret)
            goto err0;

        ret = set_byte_array(env, cls, csi, pst_device_info, "setDeviceName", (jbyte *) devi.DeviceName, sizeof(devi.DeviceName));
        if (ret)
            goto err0;

        ret = set_byte_array(env, cls, csi, pst_device_info, "setDeviceSerial", (jbyte *) devi.DeviceSerial, sizeof(devi.DeviceSerial));
        if (ret)
            goto err0;
                 goto err0;

        ret = set_int(env, cls, csi, pst_device_info, "setDeviceVersion", devi.DeviceVersion);
        if (ret)
            goto err0;

        ret = set_int(env, cls, csi, pst_device_info, "setStandardVersion", devi.StandardVersion);
        if (ret)
            goto err0;
            
        ret = set_int_array(env, cls, csi, pst_device_info, "setAsymAlgAbility", (jint *) devi.AsymAlgAbility,
                            sizeof(devi.AsymAlgAbility) / sizeof(devi.AsymAlgAbility[0]));
        if (ret)
            goto err0;
        ret = set_int(env, cls, csi, pst_device_info, "setSymAlgAbility", devi.SymAlgAbility);
        if (ret)
            goto err0;
        ret = set_int(env, cls, csi, pst_device_info, "setHashAlgAbility", devi.HashAlgAbility);
        if (ret)
            goto err0;
        ret = set_int(env, cls, csi, pst_device_info, "setBufferSize", devi.BufferSize);
        if (ret)
            goto err0;
        (*env)->DeleteLocalRef(env, cls);// jni.h方法
    }
    return c2j_errCode(ret);

err0:
    if (cls)
        (*env)->DeleteLocalRef(env, cls);
    return c2j_errCode(SDR_INARGERR);

    err1:
    return c2j_errCode(SDR_INARGERR);
}

三、java与C结构体转换的工具类

tool.c代码示例:

int set_byte_array(JNIEnv *env, jclass cls, const char *csi, jobject o, const char *ms, jbyte *dat, size_t siz) {
    char err[512];
    jmethodID met;
    jbyteArray arr;
    met = (*env)->GetMethodID(env, cls, ms, "([B)V");// 参数为byte[] 回参void
    if (!met) {
        //throw_no_such_method_exception(env, csi, ms);
        goto err0;
    }

    arr = (*env)->NewByteArray(env, siz);
    if (!arr) {
        memset(err, 0x0, sizeof(err));
        snprintf(err, sizeof(err) - 1, "(*env)->NewByteArray(%p, %lu)", env, siz);
        //throw_runtime_exception(env, err);
        goto err0;
    }
    (*env)->SetByteArrayRegion(env, arr, 0, siz, dat);
    (*env)->CallVoidMethod(env, o, met, arr);
    (*env)->DeleteLocalRef(env, arr);

    return 0;//成功
    err0:
    return 1;// 失败
}

Makefile编写

# 头文件
INCS = -I.

# 源文件 我这边生成了多个so,所以引用了多个源文件
SRCS = sdfapi.c xdmapi.c tool.c Ukey.c

# 源文件编译后对应的.o文件
OBJS = $(SRCS:.c=.o)
OBJS1 = sdfapi.o tool.o
OBJS2 = xdmapi.o tool.o
OBJS3 = Ukey.o tool.o

# 编译器
CC = gcc
CFLAGS1 = -g -fPIC $(INCS)
CFLAGS2 = -shared
DEFS = -D_SOURCE
CFLAGS3 = -L./ -ltsrs10 -ldl -lpthread -Wl,-rpath="."

# 编译规则
all : libsdf.so libxdm.so libukey.so

%.o : %.c %.h
	$(CC)  $(CFLAGS1) $(DEFS) -c $<  -o $@

libsdf.so : $(OBJS1)
	$(CC) $(CFLAGS1) $(CFLAGS2) $(OBJS1) -o $@ $(CFLAGS3)

libxdm.so : $(OBJS2)
	$(CC) $(CFLAGS1) $(CFLAGS2) $(OBJS2) -o $@ $(CFLAGS3)

libukey.so : $(OBJS3)
	$(CC) $(CFLAGS1) $(CFLAGS2) $(OBJS3) -o $@ $(CFLAGS3)

.PHONY : clean build.c

clean :
	rm -rf *.o libsdf.so libxdm.so libukey.so

使用make命令进行编译生成so文件:
示例图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值