NDK 笔记(一)

时间:2021-01-23 06:24:47

参考:https://developer.android.com/studio/projects/add-native-code.html#link-gradle

使用Android Studio 2.2以上版本、Android插件 Gradle 2.2.0以上版本,可以将C/C++代码编译成native库,然后Gradle将库打包到APK中。Java代码可以通过JNI(Java Native Interface)调用native库中的函数。

本文所用环境为为Android Studio 2.2.2。

  • 安装NDK

NDK 笔记(一)

用Android Studio集成的SDK Manager安装NDK、CMake和LLDB。其中CMake是编译工具,LLDB是调试工具。

  • 新建工程

勾选Include C++ Support

NDK 笔记(一)

到下面这一步时,有三个选项:

C++ Standard:选择要用的C++标准,我的列表里有Toolchain Default和C++ 11,由于对C++标准没要求,我直接选Default,也就是编译工具(默认为CMake)的默认配置。

Exceptions Support:如果勾选,则编译时支持C++异常处理。Android Studio会在module对应的build.gradle中的cppFlags中添加 -fexceptions,这个cppFlags会被Gradle传递给CMake。

Runtime Type Information Support:如果勾选,则支持RTTI,Android Studio会在module对应的build.gradle中的cppFlags中添加 –frtti。

注:RTTI,(Run-Time Type Identification),通过RTTI, 程序能够使用基类指针或引用来检查这些指针或引用所指的对象的实际派生类

NDK 笔记(一)

全部勾选,点击Finish完成工程的创建。

NDK 笔记(一)

工程新建完成后,可以看到如上的目录,其中:

cpp中包含了所有项目中使用的native源码文件、头文件和预编译库。native-lib.cpp是Android Studio自动生成的一个sample文件,放在module的src/main/cpp中。

External Build Files中包含了CMake或ndk-build的编译脚本。CMakeLists.txt是Android Studio自动生成的一个CMake脚本,放在module的根目录中。

  • 编译并运行

点击Run,编辑并运行这个工程,APP呈现如下的界面:

NDK 笔记(一)

下面就是编译和运行这个APP时发生的事情:

1.Gradle调用外部的编译脚本CMakeLists.txt

NDK 笔记(一)

2.CMake执行编译脚本中的命令,将C++源文件(native-lib.cpp)编译成共享对象库(libnative-lib.so),Gradle再将这个so库打包到APK中。

NDK 笔记(一)

生成的libnative-lib.so在module对应的build\intermediates\cmake\debug\obj中,如下图所示:

NDK 笔记(一)

用APK Analyser可以看到APK中打包了libnative-lib.so库:

Build->Analyze APK..,如下:

NDK 笔记(一)

NDK 笔记(一)

3.运行时,MainActivity通过System.LoadLibrary()加载native库,然后库中的native方法就可以用了。下面是MainActivity中的代码。

NDK 笔记(一)  NDK 笔记(一)

  • 添加C/C++文件到工程

1.在module的cpp文件夹中,右键,new->C++ Class或者C/C++ Source File。

新建完成后,不会马上在Android目录结构中看到文件,打开新建的文件,会提示需在编译文件中添加该文件,并且同步工程。

NDK 笔记(一)

2.在CMakeLists.txt中,添加对新建cpp文件的配置。

NDK 笔记(一)

3.点击Sync Now,同步完成后,就可以在Android目录结构下看到新建的文件了。

NDK 笔记(一)

  • CMakeLists.txt

1.CMake的编译脚本必须命名为CMakeLists.txt

如果不是,就会报错,如下:

NDK 笔记(一)

2.CMakeLists.txt最好放在module的根目录

其实放在任意目录都可以,但是文件中声明的C/C++文件路径,都是相对于编译脚本文件所在的目录。

3.CMake默认将库文件命名为:
NDK 笔记(一)

但是在使用时,仍然使用library-name导入就行了。

4.CMake 命令:

(1)cmake_minimum_required(VERSION 3.4.1) - 指定CMake最低版本

(2)add_library(...) - 声明库名称、类型、源码文件
(3)include_directories() - 指定关联的头文件目录
(4)find_library() - 定位某个NDK库,并将其路径存储为一个变量,可以在其他地方用这个变量引用NDK库
(5)target_link_libraries() - 将NDK库链接到native库中,这样native库才能调用NDK库中的函数
5.将NDK目录下的源码编译到native库中:
NDK 笔记(一)
其中,ANDROID_NDK是AndroidStudio自动定义好的变量。
6.添加其他预编译库
需要用IMPORT标志,告诉CMake,只需要引用这个预编译库(不需要进行编译)。
NDK 笔记(一)
 

然后用set_target_properties()指定库的路径。

NDK 笔记(一)

其中ANDROID_ABI这个变量列出了NDK支持的所有ABI(Application Binary Interface),用这个变量可以让CMake引用多个ABI对应的库文件。

当然,还要指定头文件路径:

NDK 笔记(一)

最后,用target_link_libraries()将预编译库链接到native库中。