JNI 总结
JNI JNI是指Java Native Interface,在编写Java程序时需要使用本地代码(C/C++)可以使用这一技术。 通常来说,要使用的本地代码有两种:C/C++源代码和经过编译的库(用在Android应用上的是.so库,需要根据运行的设备编译对应版本)。 使用JNI要做的几个部分有:确定接口,编写Java和cpp文件,编写cmake文件,加载库,使用函数。这几个步骤理论上没有顺序,按照我的实践结果,有的步骤按逻辑来执行比较方便。 前期配置 我的开发IDE是Android Studio,需要在项目中先配置好NDK和cmake插件。 在开发时,我选择了新建一个模块作为JNI部分,虽然多了一层的封装,但是自己看起来比较清楚。这里有一个小问题,在gradle版本为4.1.1时,会出现新建native Lib模块不能编译的问题,我将gradle版本升级到7.4.2解决了这个问题。如果选择新建moudle,还要在app的build.gradle中加入引用 ... dependencies { ... implementation project(path : ':nativeLib') } 如果选择在app中直接加入也很简单,在Java同级目录下创建cpp目录,并在cpp文件夹中创建CMakeLists.txt等文件就可以。 当然,以上两种都可以在创建app或模块时就选择native lab,IED会自动创建相关目录和文件。 确定接口 这里的接口指的是在Java中会调用的接口。在Java文件中,要加入native。 public static native int init(); 这里的接口也对应要编写的cpp文件。 Java文件加载库 在Java代码中除了要处理接口,还要引入库,我们编写的cpp文件也会编译成库,不要忘记加上这个库。 // cpp文件的库 System.loadLibrary("nativeLib"); // 其他库,对应名称libexample.lib System.loadLibrary("example"); 编写cpp文件 生成接口定义 Java中确定的native接口也需要在cpp中实现。 Java确定cpp文件中的函数名称有一套规则:Java_{package_and_classname}_{function_name}(JNI arguments)。包名中的点换成单下划线。需要说明的是生成函数中的两个参数: JNIEnv *:这是一个指向JNI运行环境的指针,后面我们会看到,我们通过这个指针访问JNI函数 jobject:这里指代java中的this对象 我不推荐按照这个规则直接去写,有两种方法可以生成Java能找到的cpp函数名: 将javah.exe加入环境变量并使用以下命令 javac -h . nativeLab.java java nativeLib.java javah -jni nativeLib.java 使用Android Studio 外部工具,将javah.exe作为外部工具直接使用生成头文件。 我们可以直接参照生成的头文件来编写cpp文件,在编译中,这个头文件不是必要的。 函数内容 java会将一些参数传给cpp,所以这些参数需要我们进行处理的转化。 原始类型 jint, jbyte, jshort, jlong, jfloat, jdouble, jchar, jboolean这些分别对应这java的int, byte, short, long, float, double, char and boolean。 ...