JNI中native方法的几种注册方式

2020-05-19  本文已影响0人  JasonChen8888

背景

面试NDK开发的时候,经常碰到一个问题:如何在jni中注册native函数,有几种注册方式?
答案:native方法的注册分为静态注册和动态注册

静态注册

动态注册

  1. 利用结构体 JNINativeMethod 数组记录 java 方法与 JNI 函数的对应关系;
  2. 实现 JNI_OnLoad 方法,在加载动态库后,执行动态注册;
  3. 调用 FindClass 方法,获取 java 对象;
  4. 调用 RegisterNatives 方法,传入 java 对象,以及 JNINativeMethod 数组,以及注册数目完成注册;
public native static String getStringFromJni();

C++的代码

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "jni.h"
#include <assert.h>

//定义的对应java中的定义native方法
JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz)
{
    printf("hello in c native code./n");
    return env->NewStringUTF("hello world returned to java");
}

//需要动态注册的native方法所在的类
#define JNIREG_CLAS_MAIN "com/jason/jni/JniMain"

//创建JNINativeMethod的数组,用来存放,JNINativeMethod结构变量,JNINativeMethod结构存放:注册的native方法,对应的签名,C++/C的对应的JNI方法
static JNINativeMethod gMethods[] = {
    {"getStringFromJni","()Ljava/lang/String;", native_hello }
};

static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods) {
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

/***
* 注册native方法
*/
static int registerNatives(JNIEnv* env) {
    if (!registerNativeMethods(env, JNIREG_CLAS_MAIN, gMethods, sizeof(gMethods) / sizeof(gMethods[0]))) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

/**
* 如果要实现动态注册,这个方法一定要实现
* 动态注册工作在这里进行
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!registerNatives(env)) { //注册
        return -1;
    }
    result = JNI_VERSION_1_4;
    return result;
}
typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;

介绍:

  1. name:是java中定义的native方法名
  2. signature:是用于描述方法的参数与返回值,方法的签名
  3. fnPtr 是函数指针,用来指向 jni 函数

区别:

上一篇下一篇

猜你喜欢

热点阅读