跟我一起学NDK-NDK开发环境搭建

为什么需要 NDK

总的来说 NDK 在下面两个场景派上用场

  • 进一步提升设备性能,以降低延迟或运行游戏或物理模拟等计算密集型应用
  • 重复使用您自己或其他开发者的 C 或 C++ 库

原生开发套件 (NDK) 是一套工具,使您能够在 Android 应用中使用 C 和 C++ 代码,并提供众多平台库,您可使用这些平台库管理原生 Activity 和访问实体设备组件,例如传感器和触摸输入

搭建 NDK 开发环境

如需为您的应用编译和调试原生代码,您需要以下组件:

  • Android 原生开发套件 (NDK):这套工具使您能在 Android 应用中使用 C 和 C++ 代码
  • CMake:一款外部构建工具,可与 Gradle 搭配使用来构建原生库
  • LLDB:Android Studio 用于调试原生代码的调试程序

编译原生库也可以使用 ndk-build,和 CMake 两者选一,不可混用。Android Studio2.3 版本之后 默认构建工具是 CMake,因此本教程只讲解 CMake

下载 NDK 和 CMake

当您安装 NDK 时,Android Studio 会选择可用的最新 NDK 版本。对于大多数项目,安装此默认版本的 NDK 已经足够。不过,如果您的项目需要一个或多个特定版本的 NDK,您可以下载并配置特定版本。当多个项目各自依赖于特定版本的 NDK 时,这样做有助于确保各个项目的 build 都可重现。Android Studio 会将所有版本的 NDK 安装在 sdkdir/ndk/ 目录中。

如需在 Android Studio 中安装 CMake 和默认 NDK,请执行以下操作:

  1. 打开项目后,依次点击 Tools > SDK Manager
  2. 点击 SDK Tools 标签页
  3. 选中 NDK (Side by side) 和 CMake 复选框

ndk安装

  1. 点击 OK
  2. 此时系统会显示一个对话框,告诉您 NDK 软件包占用了多少磁盘空间
  3. 点击 OK
  4. 安装完成后,点击 Finish
  5. 您的项目会自动同步 build 文件并执行构建。修正发生的所有错误

下载特定版本的 NDK

要安装特定版本的 NDK,请执行以下操作:

  1. 打开项目后,依次点击 Tools > SDK Manager
  2. 点击 SDK Tools 标签页
  3. 选中 Show Package Details 复选框
  4. 选中 NDK (Side by side) 复选框及其下方与您想要安装的 NDK 版本对应的复选框Android Studio 会将所有版本的 NDK 安装在 sdkdir/ndk/ 目录中

ndk安装

  1. 点击 OK
  2. 此时系统会显示一个对话框,告诉您 NDK 软件包占用了多少磁盘空间
  3. 点击 OK
  4. 安装完成后,点击 Finish
  5. 您的项目会自动同步 build 文件并执行构建。修正发生的所有错误

创建支持 c/c++ 的新项目

创建支持原生代码的新项目的步骤与创建任何其他 Android Studio 项目的步骤相似

  1. 在向导的 Choose your project 部分中,选择 Native C++ 项目类型
  2. 点击 Next
  3. 填写向导下一部分中的所有其他字段
  4. 点击 Next
  5. 在向导的 Customize C++ Support 部分中,您可以使用 C++ Standard 字段自定义项目。使用下拉列表选择您想要使用哪种 C++ 版本。选择 Toolchain Default 可使用默认的 CMake 设置
  6. 点击 Finish

在 Android Studio 完成新项目的创建后,请从 IDE 左侧打开 Project 窗格,然后选择 Android 视图。如图所示,Android Studio 会添加 cpp 组:

ndk项目结构

现有项目支持 c/c++

  1. 项目切换到 Project,在 main 下新建 cpp 文件夹
  2. 新建 CMakeLists.txt 文件放在 cpp 文件夹下。并新增如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cmake_minimum_required(VERSION 3.10.2)
project("testndk")

add_library(
native-lib
SHARED
native-lib.cpp )

find_library(
log-lib
log )

target_link_libraries(
native-lib
${log-lib} )
  1. 新建 native-lib.cpp 文件放在 cpp 文件夹下。并新增如下内容:
1
2
3
4
5
6
7
8
9
10
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_netease_nis_testndk_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}

中间的com_netease_nis_testndk换成自己的包名

  1. build.gradle 关联 CMake。在 android 域下添加如下内容
1
2
3
4
5
6
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.10.2'
}
}
  1. 然后就可以在应用层调用原生库了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

((TextView)findViewById(R.id.tv)).setText(stringFromJNI());
}

public native String stringFromJNI();
}

NDK 和 Gradle 插件

从上面的 NDK 开发环境搭建过程中我们并没有看到 NDK 相关的配置,那怎么就可以在应用中使用 c/c++ 代码了呢?其实 Gradle 插件指定了默认的 NDK 版本

Android Studio/Gradle 插件版本 为 AGP 版本指定的默认 NDK 版本
4.2 21.4.7075529
4.1 21.1.6352462
4.0 21.0.6113669
3.6 20.0.5594570
3.4、3.5 未指定默认版本

可以通过在 android 域中指定特定的版本来改变默认的 NDK 版本:

1
2
3
android {
ndkVersion = "major.minor.build" // 如ndkVersion "21.3.6528147"
}

构建和运行示例应用

点击 Run 图标从菜单栏运行应用后,Android Studio 会构建并启动一个应用,此应用会在您的 Android 设备或模拟器上显示文字“Hello from C++”。下面的概览介绍了在构建和运行示例应用时会发生的事件:

  1. Gradle 调用您的外部构建脚本 CMakeLists.txt
  2. CMake 按照构建脚本中的命令将 C++ 源代码文件 native-lib.cpp 编译到共享的对象库中,并将其命名为 libnative-lib.so,Gradle 随后会将后者打包到 APK 中
  3. 在运行时,应用的 MainActivity 使用 System.loadLibrary() 加载原生库。现在,应用就可以使用库的原生函数 stringFromJNI() 了
  4. MainActivity.onCreate() 调用 stringFromJNI(),后者会返回“Hello from C++”,并使用它更新 TextView 文本

运行结果

NDK 断点调试

NDK 断点调试和 Java 类似,打断点之后 Debug。只是 NDK 断点调试会另启一个 LLDB 的服务,这个服务依赖于 Host 的配置,否则会报如下错误:

没有配置host

配置 host 可以借助于 SwitchHosts,然后在 SwitchHosts 添加如下 host

1
127.0.0.1 localhost

华为手机 NDK 断点调试还会出现如下问题,目前还没找到解决方法。找到解决方法的读者可以在下方留言哈

华为手机异常