1 C++与Java的映射方案

  在Java层调用native方法时,native方法不是具体的,需要去C++层去寻找对应的真正实现。在JNI的文档中,提到其实现方案类似于实现C++继承机制的虚函数表,有兴趣的同学可以去看一下。本小节主要讲解映射规则,demo戳此

1.1 静态注册

  上篇文章已经提及,函数名主要是Java_包名_类名_方法名这样的书写方式。相应的对应数据类型的表格如下。

  1. 基本数据类型如下,除void外,一般的native类型都是在java类型前面加j。
    NDK开发入门(三)
  2. 引用数据类型如下,数组的JNI层数据类型需要以“Array”结尾,签名格式的开头都会有“[”。除了数组以外,其他的引用数据类型的签名格式都会以“;”结尾。 NDK开发入门(三)
      另外引用类型之间还有相应的继承关系。
    NDK开发入门(三)

1.2 动态注册

  动态注册需要三个步骤

  1. On_load注册函数。
  2. 填写注册信息。
  3. 自定义的函数名
//
// 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 头文件的生成方法

  1. 用javac命令生成对应的.class文件。由于使用Android Studio 内置的terminal,所以默认目录是项目根目录。注释是命令是使用方法。
javac  app/src/main/java/com/chinaso/addnative/Register.java  //javac your_class_path/class_name.java
  1. 根据第一步创建的javah命令生成相应的头文件,首先看一下这个命令的用法吧。NDK开发入门(三)
  2. 为了更清楚的描述,上一下目录结构吧。

NDK开发入门(三)
AS的Terminal默认是工程根目录。-classpath 是从中加载类路径,这个位置就是你生成.class文件的位置。-d就是输出的头文件被放到哪里。-jni就是输出符合JNI标准的头文件。另外在javah的用法说明里,在最后说明了这个类需要加全限定名,也就是包名+类名。

javah -classpath ./app/src/main/java  -d ./app/src/main/cpp  -jni  com.chinaso.addnative.Register
  1. 生成了静态注册所需要的方法名以及动态注册需要的方法签名。事实上这一步骤在动态注册或者静态注册中是可以省略的,只是提供了一种自动生成而非手动书写的办法而已。NDK开发入门(三)

2 参考文献

[1]https://blog.csdn.net/itachi85/article/details/74157262

相关文章: