一 静态注册
优点: 用javah 生成头文件方便简单
缺点:
- 每个class都需要使用javah生成一个头文件,
- 生成的名字很长书写不便;
- 初次调用时需要依据名字搜索对应的JNI层函数来建立关联关系,会影响运行效率
二 动态注册
使用一种数据结构JNINativeMethod来记录java native函数和JNI函数的对应关系
移植方便(一个java文件中有多个native方法,java文件的包名更换后)
1 动态注册的步骤
- native-lib.c文件中定义一个动态注册的方法
#include <jni.h>
#include <android/log.h>
#define TAG "Ray_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
JNIEXPORT void JNICALL native_diff
(JNIEnv *env, jclass clazz, jstring path, jstring pattern_Path, jint file_num)
{
LOGI("JNI begin 动态注册的方法 ");
}
- 声明数组(java中方法名,方法签名,c中对应实现的方法指针)
static const JNINativeMethod gMethods[] = {
{
"diff","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_diff
}
};
- 定义regist方法
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
static int registerNatives(JNIEnv* engv)
{
LOGI("registerNatives begin");
jclass clazz;
clazz = (*engv) -> FindClass(engv, "com/ray/ndk/ndk/FileUtils");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
if ((*engv) ->RegisterNatives(engv, clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
- 实现onLoad方法(jni.h中有)
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;
}
2 完整的native-lib.c 文件
//
// Created by Ray on 2020-3-21.
//
#include <android/log.h>
#include <assert.h>
#include <jni.h>
//int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#define TAG "Ray_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
/*
* Class: com_dn_tim_dn_lsn_9_FileUtils
* Method: diff
* Signature: (Ljava/lang/String;Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL native_diff
(JNIEnv *env, jclass clazz, jstring path, jstring pattern_Path, jint file_num)
{
LOGI("JNI begin 动态注册的方法 ");
}
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;
clazz = (*engv) -> FindClass(engv, "com/ray/ndk/ndk/FileUtils");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
if ((*engv) ->RegisterNatives(engv, clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
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;
}
3 java中定义的类及被实现的native方法
public class FileUtils {
static {
System.loadLibrary("native-lib");
}
public static native void diff(String path,String pattern_Path,int file_number );
}
4 调用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
diff();
}
public void diff(){
Log.d("RAY", "diff");
FileUtils.diff("ss","33" ,4 );
}
}
打印结果:
diff
jni_OnLoad begin
registerNatives begin
JNI begin 动态注册的方法