NDK还提供了交叉编译器,开发人员只需要简单地修改mk文件就可以生成特定CPU平台的动态库。
JNI开发流程
- 在java中声明native方法
声明native方法,且在类头部有加载动态库的过程,库的真实名字为加载所用名字加前缀lib,这是加载so库的规范。 - 编译java源文件得到class文件,然后通过javah命令导出JNI的头文件
javac com/ddd/example.java
javah com.ddd.example
在当前目录会产生一个com_ddd_example.h的头文件,它是javah命令自动生成的。函数名的格式遵循java_包名_类名_方法名
- 实现JNI方法,JNI方法是指java中声明的native方法,在工程的主目录下创建一个子目录,名称随意,将上一步生成的头文件复制其中,接着创建.cpp文件,include它。实现其中的方法。
- 编译so库并在java中调用so库这里采用gcc编译,切换到刚刚生成的子目录中,对于cpp编译指令如下:
gcc -shared-I /本地jdk的安装路径/include -fPIC .cpp -o libexample.so
so库编译完成后,就可以在Java程序中调用so库了,切换至主目录,执行指令
java -Djava.library.path=子目录名 com.ddd.example
其中-Djava.library.path指明了so库的路径。
NDK开发流程
- 下载并配置NDK
- 创建一个安卓项目,并声明所需的native方法如:
public static native String hello();
3.实现安卓项目中声明的native方法,在外部创建一个名为jni的目录,然后在jni目录下创建3个文件,.cpp,Android.mk和Application.mk .h中:
JNIEXPORT jstring JNICALL Java_com_aiseminar_EasyPR_PlateRecognizer_hello(JNIEnv *, jclass);
.cpp中实现其.h中的函数。
Android.mk中,LOCAL_MODULE表示模块的名称,LOCAL_SRC_FILES表示需要参与编译的源文件。
Application.mk中常用的配置项是APP_ABI,它表示CPU架构平台的类型,默认NDK编译全平台的so库,但可以指定编译特定平台的so库。
- 切换到jni目录的父目录,然后通过ndk-build命令编译产生so库
这时NDK会创建一个和jni平级的目录libs,存放so库的目录。需要注意ndk-build命令默认指定jni目录为本地源码目录。若不是则无法成功编译。
然后在app/src/main中创建一个名为jniLibs目录,将生成so库复制过去,通过AndroidStudio编译运行即可。
jniLibs目录是AndroidStudio默认目录,也可修改App build.gradle文件,jniLibs.srcDir选项指定了新的存放so库的目录。
也可以通过AndroidStudio来自动编译来产生so库。首先需要在App的build.gradle的defaultConfig区域内添加NDK选项,其中moduleName制定了模块的名称,这个名称指定看打包后的so库文件名。
ndk{
moduleName”example”
}
接着需要将JNI代码放在app/src/main/jni目录中,注意存JNI必须为jni,也可以通过如下方式指定JNI代码路径,其中jni.srcDirs指定JNI代码路径:
jni.srcDirs ‘src/main/lib_src’
经过上面的步骤,AndroidStudio就可以自动编译JNI代码了。
JNI的数据类型和类型签名
JNI调用Java方法
1 找到类名
2 找到方法id
3 调用方法
对于非静态方法要先生成类才行