在 Android 开发中,原生开发套件(NDK)允许开发者使用 C 和 C++ 代码,为应用带来高性能计算、跨平台代码复用或访问底层库的能力,要成功地将这些原生代码集成到 Android 项目中,核心在于理解和正确配置一系列关键的配置文件,这些文件如同桥梁,连接了 Gradle 构建系统与 C/C++ 编译器,确保原生代码能够被正确编译、链接并打包到最终的 APK 中。
核心配置文件概览
Android NDK 的配置主要涉及几个关键文件,它们各司其职,共同构成了原生代码的构建蓝图,现代 Android 开发主要推荐使用 CMake,
CMakeLists.txt
是最重要的配置文件。
build.gradle
负责将 NDK 构建流程集成到 Gradle 中,而传统的系统则依赖
Android.mk
和
Application.mk
。
CMakeLists.txt:现代构建脚本
CMakeLists.txt
是 CMake 构建系统的核心配置文件,也是当前 Android Studio 默认支持和推荐的方式,它定义了如何从源代码构建原生库,一个典型的
CMakeLists.txt
文件包含以下关键指令:
一个简单的示例如下:
cmake_minimum_required(VERSION 3.18.1)project("myndkapp")add_library(native-libSHAREDnative-lib.cpp)find_library(log-liblog)target_link_libraries(native-lib${log-lib})
这个例子定义了一个名为
native-lib
的共享库,其源代码是
native-lib.cpp
,并将其链接到了 Android 的日志库。
build.gradle:连接 Gradle 与 NDK
要让 Gradle 知道如何调用 CMake 或 ndk-build,你必须在模块级的
build.gradle
文件中进行配置,这主要通过
externalNativeBuild
块实现。
android {// ...defaultConfig {// ...externalNativeBuild {cmake {// 可以向 CMake 传递编译参数cppFlags "-frtti -fexceptions"arguments "-DANDROID_STL=c++_shared"}}}buildtypes {// ...}externalNativeBuild {cmake {// 指定 CMakeLists.txt 文件的路径path "src/main/cpp/CMakeLists.txt"version "3.18.1"}}}
这里的
externalNativeBuild
块有两个部分:一个在
defaultConfig
内部,用于传递特定构建变体的参数;另一个在内部,用于指定 CMake 脚本路径和版本。
Android.mk 与 Application.mk:传统构建系统
在 CMake 成为标准之前,Android 使用系统,它依赖于风格的配置文件。
虽然对于新项目不推荐使用,但在维护一些旧项目时,理解这两个文件仍然很重要。
配置文件对比
为了更清晰地理解这些文件的作用,下表进行了简要对比:
| 文件名 | 主要作用 | 使用场景 |
|---|---|---|
CMakeLists.txt
|
定义 C/C++ 源文件、编译选项、库依赖和链接规则,是现代 NDK 构建的核心。 | 所有新的 NDK 项目,使用 CMake 构建系统。 |
build.gradle
|
将 NDK 构建流程(CMake 或 ndk-build)集成到 Android Gradle 构建系统中。 | 所有 Android 项目,用于连接 Gradle 与 NDK。 |
Android.mk
|
描述单个模块的编译信息,是 ndk-build 系统的核心。 | 旧项目维护,或特定需求下使用 ndk-build 系统。 |
Application.mk
|
描述应用级别的构建参数,如目标 ABI 和 STL。 |
与
Android.mk
配合使用,用于 ndk-build 系统。
|
相关问答FAQs
问题1:CMake 和 ndk-build(使用 Android.mk)有什么区别?我应该选择哪个?
回答:
CMake 是一个跨平台的、开源的构建系统生成器,功能更强大,生态系统更活跃,并且是 Android 官方当前首推和默认支持的方案,它使用更简洁、更易读的
CMakeLists.txt
脚本,ndk-build 是基于 GNU Make 的一个构建系统,是早期的方案,配置相对繁琐,且功能扩展性不如 CMake。
对于所有新项目,强烈建议使用 CMake
,对于现有的使用 ndk-build 的旧项目,可以考虑逐步迁移到 CMake 以获得更好的支持和维护性。
问题2:如何配置我的 NDK 项目以支持不同的 CPU 架构(ABI),arm64-v8a 和 armeabi-v7a?
回答:
你可以在模块级的
build.gradle
文件中的
defaultConfig
块内,使用
ndk.abiFilters
来指定你想要支持的 ABI,这是最现代和推荐的做法。
android {// ...defaultConfig {// ...ndk {abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'}}}
这样配置后,Gradle 在构建时会只为指定的 ABI 编译原生库,从而减小 APK 体积(如果使用 APK 分包)或确保兼容性,如果你使用的是传统的 ndk-build 系统,则需要在
Application.mk
文件中设置变量,
APP_ABI := arm64-v8a armeabi-v7a
。
android studio cmake和ndk哪个好
ndroid Studio升级到2.2之后,我们可以先配置好NDK开发的一些所需工具,如图,在SDK Tools中勾选安装CMake、LLDB、NDK。
CMake: 外部构建工具。
如果你准备只使用 ndk-build 的话,可以不使用它。
LLDB: Android Studio上面调试本地代码的工具。
Android Studio自带DEMO了解CMAKEAndroid Studio升级到2.2版本之后,在创建新的project时,界面上多了一个Include C++ Support的选项。
勾选它之后将会创建一个默认的C++与JAVA混编的Demo程序。
就让我们先来看看这个官方标准Demo吧。
开始之前最好先下载好NDK,见NDK开发 从入门到放弃(一:基本流程入门了解),即在Project Structure界面Android NDK location处下载或选择正确的路径。
或者使用上方提供的工具安装方法来进行下载。
否则,创建的新project也会报错,需要配置好后clean。
File -> New -> New Project,在如下界面中勾选Include C++ Support,然后一路 Next,直到 Finish 为止即可。
项目打开后我们查看目录结构,与常规项目不同的是多了文件夹、cpp文件夹、文件,如下图:这三个东西都是NDK部分: 1. 文件夹:cmake编译好的文件, 显示支持的各种硬件等信息。
系统生成。
2. cpp文件夹:存放C/C++代码文件,文件是该Demo中自带的,可更改。
需要自己编写。
3. 文件:CMake脚本配置的文件。
需要自己配置编写。
Gradle中也有两处不同: java代码:public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {(savedInstanceState);setContentView(_main);// Example of a call to a native methodTextView tv = (TextView) findViewById(_text);(stringFromJNI());}/*** A native method that is implemented by the native-lib native library,* which is packaged with this application.*/public native String stringFromJNI();// Used to load the native-lib library on application {(native-lib);}}从的代码中我们能看到它使用的是静态注册的方式,动态注册的方式代码同传统JNI。
#include
怎么安装android sdk
展开全部分以下几个步骤:1. 下载android SDK2. 下载完成后直接安装,安装和其他的软件的安装并没有什么区别。 只要注意安装路径就好。 3. 首先下载安装android SDK tools和android SDK platform-tools.4. 下载安装都是自动进行的,只需要等待即可。 安装完成后并不能使用,需要下载SDK的各种版本的包才能使用。 5. 等待所选择的包全部下载并安装完成后就可以用开发工具进行开发了。
如何利用Capstone引擎写一个Android反汇编工具
通过Android Studio SDK Manager安装了NDK编译Capstone Engine接下来为Android交叉编译Capstone Engine# git cloneinto : Counting objects: , : Compressing objects: 100% (12/12), : Total (delta 4), reused 0 (delta 0), pack-reused Receiving objects: 100% (/), 26.10 MiB | 3.01 MiB/s, deltas: 100% (/), connectivity... done.# cd capstone# NDK=~/Library/Android/sdk/ndk-bundle/ ./ cross-android arm在当前目录中我们应该有一个名为的文件,将其复制到我们之前创建的jniLibs目录中。 接着下载一份Capstone Java bindings,并将其放入Android Studio项目中的app/libs/目录,其提供了一些方法和类帮助我们与Capstone Engine进行交互。 编译JNACapstone Java bindings利用JNA函数库加载并与Capstone预制函数库沟通,我们需要为Android编译JNA JAR并提取支持JNA的二进制库平台。 这一步,你需要安装ant:# git cloneinto : Counting objects: , : Total (delta 0), reused 0 (delta 0), pack-reused Receiving objects: 100% (/), 213.06 MiB | 4.51 MiB/s, deltas: 100% (/), connectivity... done.# cd jna# PATH=$PATH:~/Library/Android/sdk/ NDK_PLATFORM=~/Library/Android/sdk/ndk-bundle/platforms/android-21/ ant =android-arm distJNA完成编译之后,我们还需要复制一些文件到Android Studio project。 首先复制dist/到项目下的app/libs/目录,然后就像解压zip文件包一样提取dist/文件,将文件复制到项目下的app/src/main/jniLibs目录。 JNA使用的这些函数库通过JNI与本机函数库进行交互。 在一起,在一起!既然已经将所有的函数库都进行了编译,并将这些文件复制到项目下相对应的目录,我们就可以开始使用Capstone Engine。 在我们开始使用之前,我们需要保证复制到项目下的两个Java库已经被包含。 要做到这一点,在Android Studio中将他们作为文件的依赖进行增加(右键单击模块,打开模块设置,然后打开依赖关系选项卡,最后点击+按钮进行添加)添加完成之后,我们就可以在Android项目中使用Capstone了:import ;public class MainActivity extends Activity {private byte [] CODE = { 0x55, 0x48, (byte) 0x8b, 0x05, (byte) 0xb8, 0x13, 0x00, 0x00 };@Overrideprotected void onCreate(Bundle savedInstanceState) {(savedInstanceState);setContentView(_main);Capstone cs = new Capstone(_ARCH_X86, _MODE_64);[] allInsn = (CODE, 0x1000);for (int i=0; ; i++) {Log.e(CAPSTONE, allInsn[i] + + allInsn[i] + + allInsn[i]);}}}pre>














发表评论