基本概念
JNI
JNI(Java Native Interface),Java本地接口,是为方便java调用C或者C++等本地代码所封装的一层接口。由于Java的跨平台性导致本地交互能力不好,一些和操作系统相关的特性Java无法完成,于是Java提供了JNI专门用于和本地代码交互。
无论是 Linux,Windows 还是 Mac OS,或者一些汇编语言写的底层硬件驱动都是 C/C++ 写的。Java和C/C++不同 ,它不会直接编译成平台机器码,而是编译成虚拟机可以运行的Java字节码的.class文件,通过JIT(Just-In-Time)技术即时编译成本地机器码,所以有效率就比不上C/C++代码,JNI技术就解决了这一痛点,JNI 可以说是 C 语言和 Java 语言交流的适配器、中间件。其实主要是定义了一些JNI函数,让开发者可以通过调用这些函数实现Java代码调用C/C++的代码,C/C++的代码也可以调用Java的代码,这样就可以发挥各个语言的特点了。
NDK
NDK(Native Development Kit),是android提供的一个工具合集,帮助开发者快速开发C(或C++)的动态库,并能自动将.so和java应用一起打包成apk。NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出.so。
ABI
ABI(Application binary interface)应用程序二进制接口。不同的CPU 与指令集的每种组合都有定义的 ABI (应用程序二进制接口),一段程序只有遵循这个接口规范才能在该 CPU 上运行,所以同样的程序代码为了兼容多个不同的CPU,需要为不同的 ABI 构建不同的库文件。当然对于CPU来说,不同的架构并不意味着一定互不兼容。
armeabi设备只兼容armeabi;
armeabi-v7a设备兼容armeabi-v7a、armeabi;
arm64-v8a设备兼容arm64-v8a、armeabi-v7a、armeabi;
X86设备兼容X86、armeabi;
X86_64设备兼容X86_64、X86、armeabi;
mips64设备兼容mips64、mips;
mips只兼容mips;
就目前市场份额而言,绝大部分的设备都已经是armeabi-v7a、arm64-v8a,可以考虑只保留armeabi-v7a架构的SO文件,这样能获得更好的性能效果。
开发流程
本文根据版本的不同介绍了两种在Android Studio中实现NDK的方法:Android Studio 2.2 以下和2.2以上。
Android Studio 2.2 以下版本
步骤如下
- 配置Android NDK环境
- 关联Andorid Studio项目 与NDK
- 创建本地代码文件(即需要在 Android项目中调用的本地代码文件)
- 创建Android.mk文件 & Application.mk文件
- 通过ndk-build命令编译上述文件,生成.so库文件,并放入到工程文件中
- 在Andoird Studio项目中使用NDK实现JNI功能
由于我学习的时候所使用的Android Studio版本已经是3.0了,所以这种方法已经失效了。编译时报错如下:
Error:Execution failed for task ':app:compileDebugNdk'.
> Error: Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio. Please switch to a supported build system.
Consider using CMake or ndk-build integration. For more information, go to:
[https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile](https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile)
To get started, you can use the sample ndk-build script the Android
plugin generated for you at:
C:\Users\peter\MyApp\JNIDemo\app\build\intermediates\ndk\debug\Android.mk
Alternatively, you can use the experimental plugin:
[https://developer.android.com/r/tools/experimental-plugin.html](https://developer.android.com/r/tools/experimental-plugin.html)
To continue using the deprecated NDK compile for another 60 days, set
android.deprecatedNdkCompileLease=1519725194213 in gradle.properties
Android Studio 2.2 以上版本
只需要在Android Studio中的SDK tools中下载Cmake、NDK和LLDB三个工具,然后在Android Studio中新建项目的时候,在向导界面勾选C++支持选项然后创建项目就可以了。
项目创建好以后我们可以看到和普通Android项目有以下4个不同。
- main 下面增加了 cpp 目录,即放置 c/c++ 代码的地方
- module的 build.gradle 有修改
- 增加了 CMakeLists.txt 文件
- 多了一个 .externalNativeBuild 目录
详细内容可以参看Android NDK开发扫盲及最新CMake的编译使用。
由此可以总结出使用CMake编程的步骤如下:
- 新建cpp目录,写好C/C++代码。
- 创建并配置CMakeLists.txt文件。
- build.gradle文件中根据情况进行配置,CMakeLists.txt文件的路径必须配置。
- java代码中即可调用C/C++代码,运行程序。Java中调用JNI方法需要在具体的类中做以下操作:
//1、加载lib库
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
//2、声明调用的方法
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
//3、调用方法
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
小结
从一个小白的视角记录一下JNI编程需要掌握的基本概念以及自己跑个Hello world,做个学习笔记,感谢链接中作者的无私奉献。如果需要近一步学习可以参看JNI学习总结(实践篇)。