要将您的原生库项目作为 Gradle 构建依赖项包含进来,您需要向 Gradle 提供 CMake 或 ndk-build 脚本文件的路径。构建应用时,Gradle 会运行 CMake 或 ndk-build,并将共享库与您的应用打包在一起。Gradle 还使用构建脚本了解要提取到 Android Studio 项目中的文件,以便您可以从**项目**窗口中访问它们。如果您没有原生源代码的构建脚本,则需要在继续操作之前创建 CMake 构建脚本。
Android 项目中的每个模块只能链接到一个 CMake 或 ndk-build 脚本文件。例如,如果您想构建和打包来自多个 CMake 项目的输出,则需要使用一个CMakeLists.txt
文件作为您的顶级 CMake 构建脚本(然后将其链接到 Gradle),并添加其他 CMake 项目作为该构建脚本的依赖项。类似地,如果您使用的是 ndk-build,则可以在顶级Android.mk
脚本文件中包含其他 Makefile。
将 Gradle 链接到原生项目后,Android Studio 会更新**项目**窗格以在**cpp**组中显示您的源文件和原生库,并在**外部构建文件**组中显示您的外部构建脚本。
注意:在更改 Gradle 配置时,请务必通过点击工具栏中的**同步项目**来应用您的更改。此外,在更改 CMake 或 ndk-build 脚本文件(在已将其链接到 Gradle 之后)时,应通过从菜单栏中选择**构建 > 刷新链接的 C++ 项目**来使 Android Studio 与您的更改同步。
使用 Android Studio UI
您可以使用 Android Studio UI 将 Gradle 链接到外部 CMake 或 ndk-build 项目
- 打开 IDE 左侧的**项目**窗格,然后选择**Android**视图。
- 右键点击您要链接到原生库的模块(例如**app**模块),然后从菜单中选择**将 C++ 项目与 Gradle 链接**。您应该会看到一个类似于图 4 中所示的对话框。
- 从下拉菜单中选择**CMake**或**ndk-build**。
- 如果您选择**CMake**,请使用**项目路径**旁边的字段指定外部 CMake 项目的
CMakeLists.txt
脚本文件。 - 如果您选择**ndk-build**,请使用**项目路径**旁边的字段指定外部 ndk-build 项目的
Android.mk
脚本文件。如果Application.mk
文件位于与您的Android.mk
文件相同的目录中,Android Studio 也会将其包含在内。
- 如果您选择**CMake**,请使用**项目路径**旁边的字段指定外部 CMake 项目的
- 点击**确定**。
手动配置 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 {...} } }
要详细了解如何配置产品风格和构建变体,请访问配置构建变体。有关可以使用arguments
属性为 CMake 配置的变量列表,请参阅使用 CMake 变量。
包含预构建的原生库
如果希望 Gradle 打包任何外部原生构建中都不使用的预构建原生库,请将其添加到模块的src/main/jniLibs/ABI
目录中。
4.0 之前的 Android Gradle 插件版本需要在您的jniLibs
目录中包含 CMake IMPORTED
目标才能将其包含在您的应用中。如果您要从早期版本的插件迁移,则可能会遇到以下错误
* 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 应用包发布以进一步减小应用的大小,因为只有与用户设备的 ABI 匹配的原生库才会随下载一起提供。
对于使用 APK 发布的传统应用(在 2021 年 8 月之前创建),请考虑根据 ABI 配置多个 APK——而不是创建一个包含所有版本的原生库的大型 APK,Gradle 会为每个要支持的 ABI 创建一个单独的 APK,并且只打包每个 ABI 需要的文件。如果您在不指定如上所示代码示例中的abiFilters
标志的情况下为每个 ABI 配置多个 APK,则 Gradle 会构建原生库的所有支持的 ABI 版本,但仅打包您在多个 APK 配置中指定的那些版本。为避免构建不需要的原生库版本,请为abiFilters
标志和每个 ABI 的多个 APK 配置提供相同的 ABI 列表。