NDK09_静态注册与动态注册

NDK开发汇总

一 静态注册

优点: 用javah 生成头文件方便简单
缺点:

  • 每个class都需要使用javah生成一个头文件,
  • 生成的名字很长书写不便;
  • 初次调用时需要依据名字搜索对应的JNI层函数来建立关联关系,会影响运行效率

二 动态注册

使用一种数据结构JNINativeMethod来记录java native函数和JNI函数的对应关系
移植方便(一个java文件中有多个native方法,java文件的包名更换后)

1 动态注册的步骤

  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 动态注册的方法 ");

}
  1. 声明数组(java中方法名,方法签名,c中对应实现的方法指针)
static const JNINativeMethod gMethods[] = {
        {
                "diff","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_diff
        }
};

  1. 定义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;
}
  1. 实现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 动态注册的方法
发布了269 篇原创文章 · 获赞 123 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/baopengjian/article/details/105013463
今日推荐