Android NDK (JNI) 扫盲
本文介绍如何用当前流行的CMakeList.txt来配置生成JNI方法,想了解老版本通过Android.mk生成的请绕道。
配置NDK
(1)在Android Studio配置相关环境,详见File -> Setting
(2)假如有特定的编译需求,指定NDK的加载路径
编写JNI并配置build.gradle
(1)新建包含native方法的类
public class DeviceUtils {
static{
System.loadLibrary("cwauthor");
}
public static native String getDeviceInfo();
}
指定JNI代码编译生成的library,如上述工程里的cwauthor库。Jni库用了静态语句块,则会“一次编译一次运行”。这个cwauthor库自然就包含了我想要实现native方法——getDeviceInfo.
(2)在当前工程的build.gradle中配置ndk
注意这里相当于配置cwauthor库,并指定了32位/64位ARM平台运行。
生成JNI头文件
(1)编译生成.class字节码文件
这很简单,不过注意防止混淆。先删除原来工程下的build目录吧!
然后选择Build或者Make Project,这样你就会在../../build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/ ${packageName}/目录下找到DeviceUtils.class
注意,${packageName}会因为工程报名不同,目录级别有所差异。比如我工程包名为cn.cloudwalk.dynamic.authorization .utils,就会分为5级目录:
../../build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/cn/cloudwalk/dynamic/authorization/utils/DeviceUtils.class
(2)javah生成jni头文件
切换到.class文件所在目录,在Terminal中输入
javah -jni cn.cloudwalk.dynamic.authorization.utils.DeviceUtils
就会在../../build/intermediates/javac/debug/compileDebugJavaWithJavac/classes目录下生成jni头文件:
在src/main下新建jni目录,将头文件剪切至该目录。
(3)实现.h中的函数
新建C++源文件来实现头文件中的getDeviceInfo函数
复制头文件名字,保持.cpp名字和.h文件名一致(良好习惯):
然后实现.h中的函数,比如很简单的示例如下:
CMakeList配置
(1)JNI编译设置
自己撰写的jni属于jni本地资源,当需要导入第三方库,可能要重新配置build.gradle:
src/main/jni即为自己写的库(我们更愿意称为静态库,因为需要重新编译);lib下为第三方动态库(多为.so文件,不需要重新编译,运行期再加入):
(2)CMakeList编译配置
(3)撰写CMakeList.txt
CMakeList.txt负责的主要是链接,即C++编译生成库通过后,指定和Java层建立链接。也就是打包成library(否则我们一开始cwauthor库里面可是空的)。
先在工程目录下创建CMakeList.txt:
在该文本中,如果有特殊C++编译版本需求,需要一开始指定编译器:
添加本地静态编译库cwauthor:
添加第三方动态库Dev_gen(这个可以自定义,外界导入的一堆.so运行打包组成的library就叫这个名字)
然后建立链接
这样File -> Sync Project with Gradle files,然后重新Build->Make Project,通过即完成NDK编译。