如需添加您的原生库项目作为 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 也会包含此文件。
- 如果您选择 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 列表。