如需添加您的原生库项目作为 Gradle 构建依赖项,您需要向 Gradle 提供 CMake 或 ndk-build 脚本文件的路径。构建应用时,Gradle 会运行 CMake 或 ndk-build,并将共享的库与应用打包到一起。Gradle 还会使用构建脚本来了解要将哪些文件添加到 Android Studio 项目中,以便您可以从 Project 窗口访问这些文件。如果您没有原生源代码文件的构建脚本,您需要先创建 CMake 构建脚本,然后再继续。
Android 项目中的每个模块只能关联到一个 CMake 或 ndk-build 脚本文件。例如,如果您想要构建并打包来自多个 CMake 项目的输出,就需要使用一个 CMakeLists.txt 文件作为顶级 CMake 构建脚本(然后将 Gradle 关联到该脚本),并添加其他 CMake 项目作为该构建脚本的依赖项。同样,如果您使用的是 ndk-build,您可以在顶级 Android.mk 脚本文件中包含其他 Makefile。
将 Gradle 关联到原生项目后,Android Studio 会更新 Project 窗格,以在 cpp 组中显示源代码文件和原生库,并在 External Build Files 组中显示外部构建脚本。
注意:更改 Gradle 配置后,请务必点击工具栏中的 Sync Project 图标
,以便让所做的更改生效。此外,如果在将 CMake 或 ndk-build 脚本文件关联到 Gradle 之后要对文件进行更改,您应当从菜单栏中依次选择 Build > Refresh Linked C++ Projects,将 Android Studio 与您的更改进行同步。
使用 Android Studio 界面
您可以使用 Android Studio 界面将 Gradle 关联到外部 CMake 或 ndk-build 项目:
- 从 IDE 左侧打开 Project 窗格,然后选择 Android 视图。
- 右键点击您想要关联到原生库的模块(例如 app 模块),然后从菜单中选择 Link C++ Project with Gradle。您会看到一个类似于图 4 所示的对话框。
- 从下拉菜单中,选择 CMake 或 ndk-build。
- 如果您选择 CMake,请使用 Project Path 旁的字段为您的外部 CMake 项目指定
CMakeLists.txt脚本文件。 - 如果您选择 ndk-build,请使用 Project Path 旁的字段为您的外部 ndk-build 项目指定
Android.mk脚本文件。如果Application.mk文件与您的Android.mk文件位于同一目录下,Android Studio 也会包含此文件。
图 4. 使用 Android Studio 对话框关联外部 C++ 项目。
- 如果您选择 CMake,请使用 Project Path 旁的字段为您的外部 CMake 项目指定
- 点击 OK。
手动配置 Gradle
如需手动配置 Gradle 以关联到您的原生库,您需要将 externalNativeBuild 块添加到模块级 build.gradle 文件中,并使用 cmake 或 ndkBuild 块对其进行配置:
Groovy
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path "CMakeLists.txt" } } }
Kotlin
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path = file("CMakeLists.txt") } } }
注意:如果您要将 Gradle 关联到现有的 ndk-build 项目,请使用 ndkBuild 块(而不是 cmake 块),并提供指向 Android.mk 文件的相对路径。如果 Application.mk 文件与您的 Android.mk 文件位于同一目录下,Gradle 也会包含此文件。
指定可选配置
您可以在模块级 build.gradle 文件的 defaultConfig 块中配置另一个 externalNativeBuild 块,以为 CMake 或 ndk-build 指定可选参数和标记。与 defaultConfig 块中的其他属性类似,您也可以在构建配置中为每个产品变种替换这些属性。
例如,如果您的 CMake 或 ndk-build 项目定义了多个原生库和可执行文件,您可以使用 targets 属性为指定产品变种构建和打包其中的部分工件。以下代码示例说明了您可以配置的部分属性:
Groovy
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang" // Sets a flag to enable format macro constants for the C compiler. cFlags "-D__STDC_FORMAT_MACROS" // Sets optional flags for the C++ compiler. cppFlags "-fexceptions", "-frtti" } } } buildTypes {...} productFlavors { ... demo { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets "native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo" } } } paid { ... externalNativeBuild { cmake { ... targets "native-lib-paid", "my-executible-paid" } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
Kotlin
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments += listOf("-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang") // Sets a flag to enable format macro constants for the C compiler. cFlags += listOf("-D__STDC_FORMAT_MACROS") // Sets optional flags for the C++ compiler. cppFlags += listOf("-fexceptions", "-frtti") } } } buildTypes {...} productFlavors { ... create("demo") { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets += listOf("native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo") } } } create("paid") { ... externalNativeBuild { cmake { ... targets += listOf("native-lib-paid", "my-executible-paid") } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
如需详细了解如何配置产品变种和 build 变体,请参阅配置 build 变体。如需了解您可以使用 arguments 属性为 CMake 配置的变量列表,请参阅使用 CMake 变量。
添加预构建的原生库
如果您希望 Gradle 打包未在任何外部原生 build 中使用的预构建原生库,请将其添加到模块的 src/main/jniLibs/ABI 目录中。
4.0 之前的 Android Gradle 插件版本要求 CMake IMPORTED 目标必须包含在 jniLibs 目录中才能将这些目标纳入应用。如果您要从该插件的较低版本进行迁移,可能会遇到如下错误:
* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'lib/x86/libprebuilt.so'
如果您使用的是 Android Gradle 插件 4.0,请将 IMPORTED CMake 目标使用的所有库从 jniLibs 目录移出,以避免出现此错误。
指定 ABI
默认情况下,Gradle 会针对 NDK 支持的应用二进制接口 (ABI) 将您的原生库构建为单独的 .so 文件,并将这些文件全部打包到您的应用中。如果您希望 Gradle 仅构建和打包原生库的特定 ABI 配置,可以在模块级 build.gradle 文件中使用 ndk.abiFilters 标志指定这些配置,如下所示:
Groovy
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a'
}
}
buildTypes {...}
externalNativeBuild {...}
}Kotlin
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters += listOf("x86", "x86_64", "armeabi", "armeabi-v7a",
"arm64-v8a")
}
}
buildTypes {...}
externalNativeBuild {...}
}
在大多数情况下,您只需要在 ndk 块中指定 abiFilters(如上所示),因为它会指示 Gradle 构建和打包原生库的这些版本。但是,如果您想控制 Gradle 应当构建的配置,并且这些配置与您希望其打包到应用中的配置相互独立,请在 defaultConfig.externalNativeBuild.cmake 块(或 defaultConfig.externalNativeBuild.ndkBuild 块)中配置另一个 abiFilters 标志。Gradle 会构建这些 ABI 配置,但只会打包您在 defaultConfig.ndk 块中指定的配置。
建议您使用 Android App Bundle 格式发布应用以进一步减小应用的大小,因为只有与用户设备的 ABI 相匹配的原生库才会通过下载内容分发。
对于使用 APK 发布的旧版应用(创建于 2021 年 8 月之前),请考虑基于 ABI 配置多个 APK,而不是创建一个包含原生库所有版本的大型 APK。Gradle 会为您想要支持的每个 ABI 创建单独的 APK,并且仅打包每个 ABI 需要的文件。如果您为每个 ABI 配置了多个 APK,但没有像上面的代码示例中所示的那样指定 abiFilters 标志,Gradle 会为您的原生库构建所有受支持的 ABI 版本,但是仅打包您在多 APK 配置中指定的版本。为避免构建不想要的原生库版本,请为 abiFilters 标记和“一个 ABI 多个 APK”配置提供相同的 ABI 列表。