1 C++与Java的映射方案
在Java层调用native方法时,native方法不是具体的,需要去C++层去寻找对应的真正实现。在JNI的文档中,提到其实现方案类似于实现C++继承机制的虚函数表,有兴趣的同学可以去看一下。本小节主要讲解映射规则,demo戳此。
1.1 静态注册
上篇文章已经提及,函数名主要是Java_包名_类名_方法名这样的书写方式。相应的对应数据类型的表格如下。
- 基本数据类型如下,除void外,一般的native类型都是在java类型前面加j。
- 引用数据类型如下,数组的JNI层数据类型需要以“Array”结尾,签名格式的开头都会有“[”。除了数组以外,其他的引用数据类型的签名格式都会以“;”结尾。
另外引用类型之间还有相应的继承关系。
1.2 动态注册
动态注册需要三个步骤
- On_load注册函数。
- 填写注册信息。
- 自定义的函数名
//
// Created by Administrator on 2019-05-05.
//
#include "com_chinaso_addnative_Register.h"
jstring Java_com_chinaso_addnative_Register_staticRegister
(JNIEnv *jniEnv, jclass ){
return jniEnv->NewStringUTF("static Register");
}
/**
* 可以自己随便命名的本地方法,只需要在对应的数据结构中注册
* @param env
* @param jobj
* @return
*/
jstring dynamic_register(JNIEnv *env,jobject jobj){
char* str = "dynamic register";
return env->NewStringUTF(str);
}
/**
*c++ 函数名与JAVA函数名的映射表{Java中的函数名,(函数参数表)返回值签名,C++中的函数名}
* 其中参数表返回值签名是为了重载同名函数能够有所区分
*
* JNINativeMethod 结构体的数组是固有的。
* 结构体参数1:对应java类总的native方法
* 结构体参数2:函数签名
* 结构体参数3:c/c++ 种对应的方法名
*/
static JNINativeMethod gMethods[] = {
{"dynamicRegister","()Ljava/lang/String;",(void *)dynamic_register }
};
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env = NULL;
jint result = JNI_FALSE;
if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) {
return result;
}
if (env == NULL) {
return result;
}
jclass clazz = env->FindClass("com/chinaso/addnative/Register");
if (clazz == NULL) {
return result;
}
if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/ sizeof(gMethods[0]))<0) {
return result;
}
result = JNI_VERSION_1_6;
return result;
}
1.3 头文件的生成方法
- 用javac命令生成对应的.class文件。由于使用Android Studio 内置的terminal,所以默认目录是项目根目录。注释是命令是使用方法。
javac app/src/main/java/com/chinaso/addnative/Register.java //javac your_class_path/class_name.java
- 根据第一步创建的javah命令生成相应的头文件,首先看一下这个命令的用法吧。
- 为了更清楚的描述,上一下目录结构吧。
AS的Terminal默认是工程根目录。-classpath 是从中加载类路径,这个位置就是你生成.class文件的位置。-d就是输出的头文件被放到哪里。-jni就是输出符合JNI标准的头文件。另外在javah的用法说明里,在最后说明了这个类需要加全限定名,也就是包名+类名。
javah -classpath ./app/src/main/java -d ./app/src/main/cpp -jni com.chinaso.addnative.Register
- 生成了静态注册所需要的方法名以及动态注册需要的方法签名。事实上这一步骤在动态注册或者静态注册中是可以省略的,只是提供了一种自动生成而非手动书写的办法而已。