Android NDK 编译工具CMake的使用
-
- 1. 创建新 Android 项目
- 2.自定义C++的配置
- 3.分析项目结构
-
- 3.1 so库/native方法
- 3.2 原生源文件
- 3.3 构建配置
- 3.4 脚本配置
- 3.5 运行流程
- 参考资料
- Author
Android Studio 用于构建原生库的默认工具是 CMake。由于很多现有项目都使用构建工具包编译其原生代码,Android Studio 还支持 ndk-build。不过,如果您在创建新的原生库,则应使用 CMake。
创建支持原生代码的项目与创建任何其他 Android Studio 项目类似,不过前者还需要额外几个步骤:
1. 创建新 Android 项目
创建新的 Android 项目,需要选中 Include C++ Support 复选框,即支持C++的。
2.自定义C++的配置
依次
Next
后,
Create Android project
>
Target Android Devices
>
Add an Activity to Mobile
>
Configure Activity
>
Customize C++ Support
为了方便分析,Exceptions Support、Runtime Type Information Support 我们也同时勾选上,不过一般情况下可以不勾选。
在 Customize C++ Support中,我们可以自定义一下内容:
- C++ Standard :使用下拉列表选择你希望使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置。
- Exceptions Support :如果你希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将
标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。-fexceptions
- Runtime Type Information Support :如果你希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将
标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。-frtti
3.分析项目结构
先切换视图到
Project
方便查看。
对比普通新建项目的内容,可以发现示例有4个地方发生了变化:
- 添加了
目录,里面有示例 C++ 源文件cpp
,它的代码里面提供了一个简单的 C++ 函数 stringFromJNI(),此函数可以返回字符串“Hello from C++”。native-lib.cpp
-
中添加了两个部分,一个负责加载so库;一个则为native方法。MainActivity.java
-
中也添加了两个部分,一个为C++添加异常处理、RTTI的处理的支持;一个则为CMake封装构建配置,同时也提供一个相对路径给CMake的构建脚本build.gradle
;CMakeLists.txt
- 添加了
脚本文件,它的主要作用是定义了哪些文件需要编译以及和其他库的关系,即辅助Cmake进行系列的操作。CMakeLists.txt
注:native相关方法去掉报红
取消检测即可,打开 Settings>Editor>Inspections>Android>Missing JNI function 去掉勾选。
新的项目完成创建后,我们可以清晰地看到结构及内容上的变化:
3.1 so库/native方法
MainActivity.java
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
下面说明一下相关的内容:
- System.loadLibrary(“native-lib”)负责加载动态的原生库文件,
为native-lib
中定义的library。CMakeLists.txt
CMake 使用以下规范来为库文件命名:
格式: lib库名称.so
注:如果你在构建脚本中指定“native-lib”作为共享库的名称,CMake 将创建一个名称为
libnative-lib.so
的文件。不过,在 Java 代码中加载此库时,请使用你在 CMake 构建脚本中指定的名称。
- stringFromJNI为native方法与
的Java_com_brainbg_nkdcmakeall_MainActivity_stringFromJNI的相对应的。native-lib.cpp
3.2 原生源文件
native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_brainbg_nkdcmakeall_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
其中
Java_com_brainbg_nkdcmakeall_MainActivity_stringFromJNI
是根据
MainActivity.java
的
stringFromJNI()
生成的,其格式如下:
格式:Java_包名_类名_方法名
3.3 构建配置
这部分主要是关于Cmake、C++相关的构建配置。
build.gradle
android {
defaultConfig {
......
//Exceptions Support(-fexceptions)、Runtime Type Information (-frtti) 构建关联
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
}
}
}
//封装CMake构建配置
externalNativeBuild {
//提供一个相对路径给CMake构建脚本
cmake {
path "CMakeLists.txt"
}
}
}
对比ndk-build和CMake的配置
//CMake需要关联CMakeLists.txt
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
//ndk-build需要关联Android.mk
externalNativeBuild {
ndkBuild {
path file('jni/Android.mk')
}
}
3.4 脚本配置
CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
上面的配置简单说明下:
- cmake_minimum_required:CMake所需的最低版本要求,目前为3.4.1。
- add_library:
- Sets the name of the library:设置库的名称。例如指定
作为共享库的名称,那么CMake 将创建一个名称为native-lib
的库文件。libnative-lib.so
- Sets the library as a shared library:将库设置为共享库.
- Provides a relative path to your source file(s):提供源文件的相对路径
- Sets the name of the library:设置库的名称。例如指定
- find_library:
- target_link_libraries:
更多关于Cmake的用法可以查看CMake文档
3.5 运行流程
下面为官方NDK文档的流程说明:
-
调用您的外部构建脚本Gradle
。CMakeLists.txt
-
按照构建脚本中的命令将 C++ 源文件CMake
编译到共享的对象库中,并命名为native-lib.cpp
,Gradle 随后会将其打包到 APK 中。libnative-lib.so
- 运行时,应用的
会使用MainActivity
加载原生库。现在,应用可以使用库的原生函数System.loadLibrary()
。stringFromJNI()
-
调用MainActivity.onCreate()
,这将返回“Hello from C++”并使用这些文字更新stringFromJNI()
。TextView
根据本人的理解,制作了一张简单流程图:
参考资料
https://github.com/googlesamples/android-ndk/tree/master/hello-libs
https://github.com/android-ndk/ndk
https://developer.android.google.cn/studio/projects/add-native-code.html#link-gradle
https://cmake.org/cmake/help/latest/index.html#
Author
作者:Brainbg(白雨)
GitHub:https://github.com/Brainbg
博客:https://www.brainbg.com/
CSDN:https://blog.csdn.net/u014720022
简书:https://www.jianshu.com/u/94518ede7100