这几天 Android Studio 2.2 终于出了稳定版,完善了对 NDK 的支持,真可谓是「开发者的大事,大快所有人心的大好事」。

NDK 集成

这次 Android Studio 不但支持传统 NDK 项目的集成,同时也支持使用 Cmake 来组织 NDK 代码。Cmake 项目可以在 Gradle 做如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
externalNativeBuild{
cmake{
path "CMakeLists.txt"
}
}

defaultConfig {
externalNativeBuild {
cmake {
targets "target1", "target2"
arguments "-DANDROID_TOOLCHAIN=clang"
cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2"
abiFilters "armeabi-v7a", "armeabi"
}
}
}

对于传统的 NDK 项目现在可以在 Gradle 里添加如下配置块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
externalNativeBuild{
ndkBuild{
path "Android.mk"
}
}

defaultConfig {
externalNativeBuild {
ndkBuild {
targets "target1", "target2"
arguments "NDK_APPLICATION_MK:=Application.mk"
cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2"
abiFilters "armeabi-v7a", "armeabi"
}
}
}

path Android.mk 文件的路径,可以使用相对路径

targets 用来过滤需要打包进 apk 的库,可以针对不同的 product flavor 做配置。只有这里指定的 targets 才会被打包,若未配置则全部打包

abiFilters 这里最好还是再指定一次,Application.mk 里指定的似乎会被忽略。如果 NDK 项目依赖一些平台相关的库或代码并且只有部分平台的依赖,这时会报找不到文件的错误,其实是没有设置 abiFilters 导致它会去找所有平台的文件

其他

完成配置并同步 Gradle 之后,在该模块的目录下会生成一个 .externalNativeBuild 目录,目录结构为 .externalNativeBuild/ndkBuild/${ProductFlavor}/${abi}/
里面是生成的构建脚本,包含三个文件。指定了 Android.mk 及 Application.mk 的位置,ndk-build 命令,编译参数及 toolchains 配置。
并且从生成的脚本中也可以看出这里已经可以根据 Gradle 中的 Debug/Release 模式生成相应的编译命令了。

  • android_gradle_build.json
  • ndkBuild_build_command.txt
  • ndkBuild_build_output.txt

如此看来 Gradle 采取的是根据我们的配置生成对应的脚本,在外部执行编译脚本,再将结果进行打包的策略,这样便使原来的项目无缝迁移,同时也为 Cmake 这样的组织方式提供了扩展。

另外现在可以针对不同渠道做定制了。可以通过在编译器参数中定义宏的方式将参数传进 JNI 中,再在 JNI 代码中做对应处理。

参考资料

  1. Add C and C++ Code to Your Project
  2. Android Studio 2.2