静态注册
每个class都需要使用javah生成一个头文件,并且生成的名字很长书写不便;初次调用时需要依据名字搜索对应的JNI层函数来建立关联关系,会影响运行效率
用javah 生成头文件方便简单
动态注册
使用一种数据结构JNINativeMethod来记录java native函数和JNI函数的对应关系
移植方便(一个java文件中有多个native方法,java文件的包名更换后)
自己实现动态注册(具体原理不进行深入,可以自己参考源码,从System.loadLibrary拆解)
//FileUtils
public class FileUtils {
public static native void diff(String path,String pattern_path,int fileNum);
static {
//不需要后缀是因为内部有进行判断
System.loadLibrary("native-lib");
}
}
native-lib.c
//为了将log输出到控制台
#include <android/log.h>
#include <assert.h>
//int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#define TAG "Tim_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
JNIEXPORT void JNICALL native_diff
(JNIEnv *env, jclass clazz, jstring path, jstring pattern_Path, jint file_num)
{
LOGI("JNI begin 动态注册的方法 ");
}
//JNINativeMethod是一个结构体,gmethods是一个结构体数组,定义的是需要注册的方面名,对应jni的方法名,方法的返回值已经参数签名
//typedef struct {
// const char* name; /*Java 中函数的名字*/
// const char* signature; /*描述了函数的参数和返回值*/
// void* fnPtr; /*函数指针,指向 C 函数*/
// } JNINativeMethod;
static const JNINativeMethod gMethods[] = {
{
"diff","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_diff
}
};
//进行方法注册
static int registerNatives(JNIEnv* engv)
{
LOGI("registerNatives begin");
jclass clazz;
//com/zzq/tim/dn_lsn_9/FileUtils 是diff方法所在的路径
clazz = (*engv) -> FindClass(engv, "com/zzq/tim/dn_lsn_9/FileUtils");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
//if里面的条件判断是仿照官方的写法
if ((*engv) ->RegisterNatives(engv, clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
//重写JNI_OnLoad实现,如果找到JNI_OnLoad实现,则会执行动态注册,否则就会进行静态注册
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
LOGI("jni_OnLoad begin");
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGI("ERROR: GetEnv failed\n");
return -1;
}
assert(env != NULL);
registerNatives(env);
return JNI_VERSION_1_4;
}
网友评论