JNI学习总结(基础篇)

基本概念

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。

JNI学习总结(基础篇)_第1张图片
NDK特点

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 以下版本

步骤如下

  1. 配置Android NDK环境
  2. 关联Andorid Studio项目 与NDK
  3. 创建本地代码文件(即需要在 Android项目中调用的本地代码文件)
  4. 创建Android.mk文件 & Application.mk文件
  5. 通过ndk-build命令编译上述文件,生成.so库文件,并放入到工程文件中
  6. 在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++支持选项然后创建项目就可以了。


JNI学习总结(基础篇)_第2张图片
勾选支持C++选项

项目创建好以后我们可以看到和普通Android项目有以下4个不同。

  • main 下面增加了 cpp 目录,即放置 c/c++ 代码的地方
  • module的 build.gradle 有修改
  • 增加了 CMakeLists.txt 文件
  • 多了一个 .externalNativeBuild 目录

JNI学习总结(基础篇)_第3张图片
项目目录

详细内容可以参看 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学习总结(实践篇)。

参考文献

  • 向您的项目添加 C 和 C++ 代码(Google官方文档)
  • Android:JNI 与 NDK到底是什么?(含实例教学)
  • Android NDK开发扫盲及最新CMake的编译使用
  • Android Studio 手把手教你NDK打包SO库文件,并提供对应API 使用它(赋demo)
  • Android 开发艺术探索——JNI和NDK编程
  • Android Studio NDK及so文件开发(一)
  • NDK开发 从入门到放弃(七:Android Studio 2.2 CMAKE 高效NDK开发)

你可能感兴趣的:(JNI学习总结(基础篇))