Android JNI 注册的两种方式

Android JNI 开发时,如何注册 JNI 的方法,Java 才能调用,下面说一下 JNI 的两种注册方法。

第一种方法:静态注册

所谓静态注册就是调用 java 的命令工具 javah 来生成头文件,然后再实现头文件中的所有函数即可。这种方法比较简单,首先在命令行中(我这里使用的是 windows cmd,linux、mac 是一样的),进入到 src 目录下,然后执行:

1
$ javah -d E:\SourceCode\Android\JniTest\ -jni com.coolerfall.HelloJni

其中 - d 表示生成的头文件的输出目录,可以自行设置,com.coolerfall.HelloJni 是包含有 native 方法的类,native 方法如:

1
public static native void init();

最后生成一个 com_coolerfall_player_HelloJni.h 头文件,接下来就可以新建一个 c 文件实现这些函数就 ok 了。

第二种方法:动态注册

静态方法虽然用起来方便,只需要使用一句命令行就搞定了,但是这种方法我们不知道 jni 的注册过程是怎样的,而且如果新添加一个方法后,又得重新生成一次,比较麻烦,动态注册就可以避免这个问题。和静态注册的区别在于,不使用 javah,而由我们自己来写注册函数等等。
  我们可以新建一个 c 文件,比如 init.c,然后在里面添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <jni.h>

static JNINativeMethod g_methods[] = {
{"init", "()V", (void *)init},
{"start", "(Ljava/lang/String;JJ)V", (void *)start},
};

int register_native_methods(JNIEnv* env, const char* class_name,
JNINativeMethod* methods, int num_methods)
{
jclass clazz;
clazz = (*env)->FindClass(env, class_name);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, methods, num_methods) < 0) {
return JNI_FALSE;
}

return JNI_TRUE;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = NULL;

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

if (!register_native_methods(env, "com/coolerfall/HelloJni", g_methods,
sizeof(g_methods) / sizeof(g_methods[0])))
{
return 0;
}

return JNI_VERSION_1_4;
}

Java 层调用 System.loadLibrary (“xxx”) 的时候,会首先进入 JNI_OnLoad 这个函数里面,因此,我们就在这里面调用 register_native_methods 对 JNI 的一些列方法进行注册,最终在 register_native_methods 调用了 jni 函数 RegisterNatives 来对 native 方法注册到对应的类上去,这样就完成了 jni 的注册,java 就可以调用 jni 的方法了。使用这种方法时,添加一个 native 方法就非常方便了,直接在 g_methods 数组里面添加新的方法即可。

关于 g_methods 数组里面方法的签名规则可以查看 Android JNI 类型、方法签名规范