利用 Android Studio 中的 Gradle 构建系统,您可以轻松地将外部二进制文件或其他库模块作为依赖项添加到您的 build 中。这些依赖项可位于您的计算机上或远程仓库中,并且它们声明的所有传递依赖项也会自动包含在内。 本页介绍了如何在您的 Android 项目中使用依赖项,包括有关 Android Plugin for Gradle 特有的行为和配置的详细信息。如需更深入地了解 Gradle 依赖项的概念,您还应该参阅 Gradle 依赖项管理指南。但请注意,您的 Android 项目只能使用本页上定义的依赖项配置。
依赖项类型
如需向您的项目添加依赖项,请在模块的 build.gradle
文件的 dependencies
代码块中指定依赖项配置,如 implementation
。
例如,应用模块的以下 build.gradle
文件包含三种不同类型的依赖项:
Groovy
plugins { id 'com.android.application' } android { ... } dependencies { // Dependency on a local library module implementation project(':mylibrary') // Dependency on local binaries implementation fileTree(dir: 'libs', include: ['*.jar']) // Dependency on a remote binary implementation 'com.example.android:app-magic:12.3' }
Kotlin
plugins { id("com.android.application") } android { ... } dependencies { // Dependency on a local library module implementation(project(":mylibrary")) // Dependency on local binaries implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) // Dependency on a remote binary implementation("com.example.android:app-magic:12.3") }
其中每种依赖项配置都要求不同种类的库依赖项,如下所示:
- 本地库模块依赖项
-
Groovy
implementation project(':mylibrary')
Kotlin
implementation(project(":mylibrary"))
这声明了对一个名为“mylibrary”(此名称必须与您的
settings.gradle
文件中使用include:
定义的库名称相符)的 Android 库模块的依赖关系。 在构建您的应用时,构建系统会编译该库模块,并将生成的编译内容打包到应用中。 - 本地二进制文件依赖项
-
Groovy
implementation fileTree(dir: 'libs', include: ['*.jar'])
Kotlin
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
Gradle 声明了对项目的
module_name/libs/
目录中 JAR 文件的依赖关系(因为 Gradle 会读取build.gradle
文件的相对路径)。或者,您也可以按如下方式指定各个文件:
Groovy
implementation files('libs/foo.jar', 'libs/bar.jar')
Kotlin
implementation(files("libs/foo.jar", "libs/bar.jar"))
- 远程二进制文件依赖项
-
Groovy
implementation 'com.example.android:app-magic:12.3'
Kotlin
implementation("com.example.android:app-magic:12.3")
这实际上是以下代码的简写形式:
Groovy
implementation group: 'com.example.android', name: 'app-magic', version: '12.3'
Kotlin
implementation(group = "com.example.android", name = "app-magic", version = "12.3")
这声明了对“com.example.android”命名空间组内的 12.3 版“app-magic”库的依赖关系。
注意:此类远程依赖项要求您声明 Gradle 应在其中查找库的相应远程仓库。 如果本地不存在相应的库,那么当 build 需要它时(例如,当您点击 Sync Project with Gradle Files 图标
或运行 build 时),Gradle 会从远程站点提取它。
如果您在编译时依赖 AGP 依赖项,请务必将其添加为显式依赖项。由于 AGP 在内部使用 api/implementation
配置,因此某些工件可能会从您的编译类路径中移除,而编译类路径可能会更改。
原生依赖项
从 Android Gradle 插件 4.0 开始,也可以按照本页所述的方式导入原生依赖项。
对提供原生库的 AAR 的依赖会自动使这些库可供 externalNativeBuild
所使用的构建系统使用。如需从代码访问这些库,您必须在原生构建脚本中链接到这些库。请参阅本页中的使用原生依赖项。
依赖项配置
在 dependencies
代码块内,您可以从多种不同的依赖项配置中选择其一(如上面所示的 implementation
)来声明库依赖项。每种依赖项配置都向 Gradle 提供了有关如何使用该依赖项的不同说明。下表介绍了您可以对 Android 项目中的依赖项使用的各种配置。此表还将这些配置与自 Android Gradle 插件 3.0.0 起废弃的配置进行了比较。
配置 | 行为 |
---|---|
implementation |
Gradle 会将依赖项添加到编译类路径,并将依赖项打包到 build 输出。不过,当您的模块配置 implementation 依赖项时,会让 Gradle 了解您不希望该模块在编译时将该依赖项泄露给其他模块。也就是说,其他模块只有在运行时才能使用该依赖项。
使用此依赖项配置代替 |
api |
Gradle 会将依赖项添加到编译类路径和 build 输出。当一个模块包含 api 依赖项时,会让 Gradle 了解该模块要以传递方式将该依赖项导出到其他模块,以便这些模块在运行时和编译时都可以使用该依赖项。
此配置的行为类似于 |
compileOnly |
Gradle 只会将依赖项添加到编译类路径(也就是说,不会将其添加到 build 输出)。如果您创建 Android 模块时在编译期间需要相应依赖项,但它在运行时可有可无,此配置会很有用。
如果您使用此配置,那么您的库模块必须包含一个运行时条件,用于检查是否提供了相应依赖项,然后适当地改变该模块的行为,以使该模块在未提供相应依赖项的情况下仍可正常运行。这样做不会添加不重要的瞬时依赖项,因而有助于减小最终应用的大小。
此配置的行为类似于
注意:您不能将 |
runtimeOnly |
Gradle 只会将依赖项添加到 build 输出,以便在运行时使用。也就是说,不会将其添加到编译类路径。
此配置的行为类似于 apk (现已废弃)。
|
annotationProcessor |
如需添加对作为注解处理器的库的依赖,您必须使用 如果 JAR 文件包含以下文件,则 Android Gradle 插件会假定依赖项是注解处理器:
如果插件检测到编译类路径上包含注解处理器,则会产生 build 错误。 注意:Kotlin 项目应使用 kapt 声明注解处理器依赖项。 |
lintChecks |
使用此配置可以添加您希望 Gradle 在构建项目时执行的 lint 检查。 注意:使用 Android Gradle 插件 3.4.0 及更高版本时,此依赖项配置不再将 lint 检查打包在 Android 库项目中。如需将 lint 检查依赖项包含在 AAR 库中,请使用下面介绍的 |
lintPublish |
在 Android 库项目中使用此配置可以添加您希望 Gradle 编译成 lint.jar 文件并打包在 AAR 中的 lint 检查。这会使得使用 AAR 的项目也应用这些 lint 检查。如果您之前使用 lintChecks 依赖项配置将 lint 检查添加到已发布的 AAR 中,则需要迁移这些依赖项以改用 lintPublish 配置。
Groovydependencies { // Executes lint checks from the ':checks' project at build time. lintChecks project(':checks') // Compiles lint checks from the ':checks-to-publish' into a // lint.jar file and publishes it to your Android library. lintPublish project(':checks-to-publish') } Kotlindependencies { // Executes lint checks from the ":checks" project at build time. lintChecks(project(":checks")) // Compiles lint checks from the ":checks-to-publish" into a // lint.jar file and publishes it to your Android library. lintPublish(project(":checks-to-publish")) } |
apk
|
Gradle 只会将依赖项添加到 build 输出,以便在运行时使用。也就是说,不会将其添加到编译类路径。 此配置已废弃(在 AGP 1.0-4.2 中可用)。 |
compile
|
Gradle 会将依赖项添加到编译类路径和 build 输出,并将依赖项导出到其他模块。此配置已废弃(在 AGP 1.0-4.2 中可用)。 |
provided
|
Gradle 只会将依赖项添加到编译类路径(也就是说,不会将其添加到 build 输出)。此配置已废弃(在 AGP 1.0-4.2 中可用)。 |
以上所有配置会将依赖项应用于所有 build 变体。如果您只想为特定的 build 变体源代码集或测试源代码集声明依赖项,则必须将配置名称的首字母大写,并在其前面加上 build 变体或测试源代码集的名称作为前缀。
例如,如需只向“free”产品变种添加 implementation
依赖项(使用远程二进制文件依赖项),请使用如下所示的代码:
Groovy
dependencies { freeImplementation 'com.google.firebase:firebase-ads:9.8.0' }
Kotlin
dependencies { freeImplementation("com.google.firebase:firebase-ads:9.8.0") }
不过,如果您想为将产品变种和 build 类型组合在一起的变体添加依赖项,就必须在 configurations
代码块中初始化配置名称。以下示例向“freeDebug”build 变体添加了 runtimeOnly
依赖项(使用本地二进制文件依赖项)。
Groovy
configurations { // Initializes a placeholder for the freeDebugRuntimeOnly dependency configuration. freeDebugRuntimeOnly {} } dependencies { freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar']) }
Kotlin
// Initializes a placeholder for the freeDebugRuntimeOnly dependency configuration. val freeDebugRuntimeOnly by configurations.creating dependencies { freeDebugRuntimeOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) }
如需为本地测试和插桩测试添加 implementation
依赖项,请使用如下所示的代码:
Groovy
dependencies { // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' }
Kotlin
dependencies { // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") }
不过,某些配置在这种情况下没有意义。例如,因为其他模块不能依赖于 androidTest
,所以如果您使用 androidTestApi
配置,会收到以下警告:
WARNING: Configuration 'androidTestApi' is obsolete and has been replaced with 'androidTestImplementation'.
添加注释处理器
如果将注释处理器添加到编译类路径,您将看到一条与以下内容类似的错误消息:
Error: Annotation processors must be explicitly declared now.
如需解决此错误,请使用 annotationProcessor
配置依赖项,将注解处理器添加到您的项目,如下所示:
Groovy
dependencies { // Adds libraries defining annotations to only the compile classpath. compileOnly 'com.google.dagger:dagger:version-number' // Adds the annotation processor dependency to the annotation processor classpath. annotationProcessor 'com.google.dagger:dagger-compiler:version-number' }
Kotlin
dependencies { // Adds libraries defining annotations to only the compile classpath. compileOnly("com.google.dagger:dagger:version-number") // Adds the annotation processor dependency to the annotation processor classpath. annotationProcessor("com.google.dagger:dagger-compiler:version-number") }
注意:Android Plugin for Gradle 3.0.0 及更高版本不再支持 android-apt
插件。
向注解处理器传递参数
如果需要向注解处理器传递参数,您可以使用模块 build 配置中的 AnnotationProcessorOptions
代码块执行此操作。例如,如果要以键值对形式传递基元数据类型,您可以使用 argument
属性,如下所示:
Groovy
android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { argument 'key1', 'value1' argument 'key2', 'value2' } } } }
Kotlin
android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments += mapOf("key1" to "value1", "key2" to "value2") } } } }
不过,在使用 Android Gradle 插件 3.2.0 及更高版本时,您需要使用 Gradle 的 CommandLineArgumentProvider
接口传递表示文件或目录的处理器参数。
借助 CommandLineArgumentProvider
,您或注解处理器创建者可将增量 build 属性类型注解应用于每个参数,从而提高增量 build 和缓存整洁 build 的正确性和性能。
例如,下面的类实现了 CommandLineArgumentProvider
并注释了处理器的每个参数。此外,此示例还使用了 Groovy 语言语法,并且直接包含在模块的 build.gradle
文件中。
Groovy
class MyArgsProvider implements CommandLineArgumentProvider { // Annotates each directory as either an input or output for the // annotation processor. @InputFiles // Using this annotation helps Gradle determine which part of the file path // should be considered during up-to-date checks. @PathSensitive(PathSensitivity.RELATIVE) FileCollection inputDir @OutputDirectory File outputDir // The class constructor sets the paths for the input and output directories. MyArgsProvider(FileCollection input, File output) { inputDir = input outputDir = output } // Specifies each directory as a command line argument for the processor. // The Android plugin uses this method to pass the arguments to the // annotation processor. @Override Iterable<String> asArguments() { // Use the form '-Akey[=value]' to pass your options to the Java compiler. ["-AinputDir=${inputDir.singleFile.absolutePath}", "-AoutputDir=${outputDir.absolutePath}"] } } android {...}
Kotlin
class MyArgsProvider( // Annotates each directory as either an input or output for the // annotation processor. @get:InputFiles // Using this annotation helps Gradle determine which part of the file path // should be considered during up-to-date checks. @get:PathSensitive(PathSensitivity.RELATIVE) val inputDir: FileCollection, @get:OutputDirectory val outputDir: File ) : CommandLineArgumentProvider { // Specifies each directory as a command line argument for the processor. // The Android plugin uses this method to pass the arguments to the // annotation processor. override fun asArguments(): Iterable<String> { // Use the form '-Akey[=value]' to pass your options to the Java compiler. return listOf("-AinputDir=${inputDir.singleFile.absolutePath}", "-AoutputDir=${outputDir.absolutePath}") } } android {...}
定义一个实现 CommandLineArgumentProvider
的类后,您需要创建一个实例,并使用 annotationProcessorOptions.compilerArgumentProvider
方法将该实例传递给 Android 插件,如下所示:
Groovy
// This is in your module's build.gradle file. android { defaultConfig { javaCompileOptions { annotationProcessorOptions { // Creates a new MyArgsProvider object, specifies the input and // output paths for the constructor, and passes the object // to the Android plugin. compilerArgumentProvider new MyArgsProvider(files("input/path"), new File("output/path")) } } } }
Kotlin
// This is in your module's build.gradle file. android { defaultConfig { javaCompileOptions { annotationProcessorOptions { // Creates a new MyArgsProvider object, specifies the input and // output paths for the constructor, and passes the object // to the Android plugin. compilerArgumentProvider(MyArgsProvider(files("input/path"), file("output/path"))) } } } }
如需详细了解实现 CommandLineArgumentProvider
如何帮助提高 build 性能,请阅读缓存 Java 项目。
停用注解处理器错误检查
如果编译类路径中的依赖项包含您不需要的注解处理器,您可以通过将以下代码添加到 build.gradle
文件来停用错误检查。请注意,您添加到编译类路径中的注解处理器仍不会被添加到处理器类路径中。
Groovy
android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { includeCompileClasspath false } } } }
Kotlin
android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { argument("includeCompileClasspath", "false") } } } }
如果您使用 Kotlin 和 kapt:
Groovy
android { ... defaultConfig { ... kapt { includeCompileClasspath false } } }
Kotlin
android { ... defaultConfig { ... kapt { includeCompileClasspath = false } } }
如果在将项目的注解处理器迁移到处理器类路径后遇到问题,您可以通过将 includeCompileClasspath
设为 true
,允许编译类路径中包含注解处理器。不过,不建议将此属性设为 true
,在 Android 插件的未来更新中将会移除用来执行此操作的选项。
排除传递依赖项
随着应用的范围不断扩大,它可能会包含许多依赖项,包括直接依赖项和传递依赖项(应用中导入的库所依赖的库)。
如需排除不再需要的传递依赖项,您可以使用 exclude
关键字,如下所示:
Groovy
dependencies { implementation('some-library') { exclude group: 'com.example.imgtools', module: 'native' } }
Kotlin
dependencies { implementation("some-library") { exclude(group = "com.example.imgtools", module = "native") } }
从测试配置中排除传递依赖项
如果您需要从测试中排除某些传递依赖项,上面所示的代码示例可能无法按预期发挥作用。这是因为,测试配置(例如 androidTestImplementation
)扩展了模块的 implementation
配置。也就是说,当 Gradle 解析配置时,测试配置始终包含 implementation
依赖项。
因此,如需从测试中排除传递依赖项,则必须在执行代码时执行此操作,如下所示:
Groovy
android.testVariants.all { variant -> variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp' variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp' }
Kotlin
android.testVariants.all { compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp") runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp") }
注意:您仍可在依赖项代码块中使用 exclude
关键字(如排除依赖项部分的原始代码示例所示),以省略测试配置特有的(即其他配置不包含的)传递依赖项。
配置 Wear OS 应用依赖项
配置 Wear OS 模块的依赖项与配置其他任何模块的依赖项相似;也就是说,Wear OS 模块使用相同的依赖项配置,如 implementation
和 compileOnly
。
Wear 模块还支持变体感知型依赖项管理机制。 因此,如果您的基础应用模块依赖于一个 Wear 模块,则基础模块的每个变体都会使用该 Wear 模块的匹配变体。
远程仓库
当您的依赖项不是本地库或文件树时,Gradle 会在 settings.gradle
文件的 dependencyResolutionManagement { repositories {...} }
代码块中指定的所有在线仓库中查找相关文件。
各个仓库的列出顺序决定了 Gradle 在这些仓库中搜索各个项目依赖项的顺序。例如,如果从仓库 A 和 B 均可获得某个依赖项,而您先列出了仓库 A,则 Gradle 会从仓库 A 下载该依赖项。
默认情况下,新的 Android Studio 项目会在项目的 settings.gradle
文件中将 Google 的 Maven 制品库和 Maven 中央制品库指定为仓库位置,如下所示:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
如果您要从本地仓库中获取某些内容,请使用 mavenLocal()
:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() mavenLocal() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() mavenLocal() } }
或者,您也可以按如下方式声明特定的 Maven 或 Ivy 仓库:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url 'https://repo.example.com/maven2' } maven { url 'file://local/repo/' } ivy { url 'https://repo.example.com/ivy' } } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven(url = "https://repo.example.com/maven2") maven(url = "file://local/repo/") ivy(url = "https://repo.example.com/ivy") } }
如需了解详情,请参阅 Gradle 仓库指南。
Google 的 Maven 制品库
Google 的 Maven 制品库中提供了以下 Android 库的最新版本:
- AndroidX 库
- 架构组件库
- 约束布局库
- AndroidX 测试
- 数据绑定库
- Android 免安装应用库
- Wear OS
- Google Play 服务
- Google Play 结算库
- Firebase
您可以在 Google 的 Maven 制品库索引中查看所有可用的工件(如需了解以编程方式访问,请参阅下文)。
如需将其中某个库添加到您的 build 中,请在顶级 build.gradle
文件中包含 Google 的 Maven 制品库:
Groovy
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() // If you're using a version of Gradle lower than 4.1, you must instead use: // maven { // url 'https://maven.google.com' // } // An alternative URL is 'https://dl.google.com/dl/android/maven2/'. } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() // If you're using a version of Gradle lower than 4.1, you must instead use: // maven { // url = "https://maven.google.com" // } // An alternative URL is "https://dl.google.com/dl/android/maven2/". } }
然后,将所需的库添加到模块的 dependencies
代码块中。例如,appcompat 库如下所示:
Groovy
dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' }
Kotlin
dependencies { implementation("com.android.support:appcompat-v7:28.0.0") }
不过,如果您在尝试使用旧版上述库时依赖项失败,则表明 Maven 制品库中未提供该版本,您必须从离线仓库获取该库。
以编程方式访问
如需以编程方式访问 Google 的 Maven 工件,可以从 maven.google.com/master-index.xml 获取工件组的 XML 列表。 然后,您可以从以下位置查看任意组的库名称和版本信息:
maven.google.com/group_path/group-index.xml
例如,android.arch.lifecycle 组中的库就列在 maven.google.com/android/arch/lifecycle/group-index.xml 中。
您也可以从以下位置下载 POM 和 JAR 文件:
maven.google.com/group_path/library/version/library-version.ext
例如:maven.google.com/android/arch/lifecycle/compiler/1.0.0/compiler-1.0.0.pom。
SDK 管理器中的离线仓库
对于无法从 Google Maven 制品库中获得的库(通常是旧版库),您必须从 SDK 管理器下载离线 Google 仓库软件包。
然后,您可以照常将这些库添加到 dependencies
代码块中。
离线库保存在 android_sdk/extras/
中。
Android Gradle 插件可以使用的原生依赖项
AAR 库可以包含 Android Gradle 插件可以使用的原生依赖项。AGP 还能生成用于向使用者公开原生库的 AAR。
使用原生依赖项
从 Android Gradle 插件 4.0 开始,我们已支持从您的 build.gradle
文件所关联的 AAR 中导入 C/C++ 依赖项。Gradle 会自动将这些依赖项提供给原生构建系统,但构建系统必须经过配置才能使用导入的库和头文件。由于 C/C++ 依赖项会以 AAR 的形式分发,因此以下关于通用 AAR 的链接可能很有用:
- 创建 Android 库,可获取通用 AAR 文档,并了解如何将其集成到您的项目中,尤其是当您想要使用 AAR 作为本地 C/C++ 依赖项时。
- 添加 build 依赖项,了解有关如何将依赖项(尤其是远程依赖项)添加到您的
build.gradle
文件。
本文档重点介绍了如何配置原生构建系统,并假定您已将 C/C++ 依赖项 AAR 添加到您项目的 Gradle 构建环境中。
AAR 中的原生依赖项
Gradle 模块中的 AAR 依赖项可公开原生库供您的应用使用。在 AAR 中,prefab
目录包含 Prefab 软件包,后者包含原生依赖项的头文件和库。
每个依赖项最多可公开一个包含一个或多个模块的 Prefab 软件包。Prefab 模块是一个单独的库,它可以是共享库或静态库,也可以是仅针对头文件的库。
软件包和模块的名称均已知时,才能使用相应库。按照惯例,软件包名称应与 Maven 工件名称相匹配,模块名称应与 C/C++ 库名称相匹配,但并非必须如此。请参考相应依赖项的文档来确定依赖项所用的名称。
构建系统配置
必须为您的 Android Gradle 模块启用 prefab
功能。
为此,请将以下内容添加到您模块的 build.gradle
文件的 android
代码块中:
Groovy
buildFeatures { prefab true }
Kotlin
buildFeatures { prefab = true }
(可选)在项目的 gradle.properties
文件中配置一个版本:
android.prefabVersion=2.0.0
通常,所选的默认 AGP 版本可满足您的需求。仅当在需要解决某个 bug 或想获取某个新功能时,才需要选择其他版本。
每个依赖项都会向您的 build 公开一个 Android.mk
文件。这些文件是通过 import-module 命令导入的。此命令会搜索其路径与 build 的导入目录(由 import-add-path
配置)中的给定路径匹配的 Android.mk
文件,并公开为您的 build 指定的模块。例如,如果您的应用已定义 libapp.so
,且使用了 cURL,那么您的 Android.mk
文件应包含以下内容:
include $(CLEAR_VARS)
LOCAL_MODULE := libapp
LOCAL_SRC_FILES := app.cpp
LOCAL_SHARED_LIBRARIES := curl
include $(BUILD_SHARED_LIBRARY)
# If you don't need your project to build with NDKs older than r21, you can omit
# this block.
ifneq ($(call ndk-major-at-least,21),true)
$(call import-add-path,$(NDK_GRADLE_INJECTED_IMPORT_PATH))
endif
$(call import-module,prefab/curl)
请注意,只有在使用 NDK r21 之前的版本时才需要使用显式 import-add-path
。从 r21 开始,系统会自动将 NDK_GRADLE_INJECTED_IMPORT_PATH
添加到导入路径。
app.cpp
现在能够执行 #include "curl/curl.h"
,系统会在构建时自动将 libapp.so
与 libcurl.so
相关联,并将 libcurl.so
包含在应用中。
在 AAR 中发布原生库
在 AGP 4.1 中首次添加了创建原生 AAR 的功能。
如需导出原生库,请将以下代码添加到库项目的 build.gradle
文件的 android
代码块中:
Groovy
buildFeatures { prefabPublishing true } prefab { mylibrary { headers "src/main/cpp/mylibrary/include" } myotherlibrary { headers "src/main/cpp/myotherlibrary/include" } }
Kotlin
buildFeatures { prefabPublishing = true } prefab { create("mylibrary") { headers = "src/main/cpp/mylibrary/include" } create("myotherlibrary") { headers = "src/main/cpp/myotherlibrary/include" } }
在本例中,您的 ndk-build 或 CMake 外部原生 build 中的 mylibrary
和 myotherlibrary
库会打包到您的 build 生成的 AAR 中,并且各自会将头文件从指定的目录导出到依赖于它们的项。
依赖项顺序
依赖项的列出顺序指明了每个库的优先级:第一个库的优先级高于第二个,第二个库的优先级高于第三个,依此类推。在合并资源或将清单元素从库中合并到应用中时,此顺序很重要。
例如,如果您的项目声明以下内容:
- 依赖
LIB_A
和LIB_B
(按此顺序) LIB_A
依赖于LIB_C
和LIB_D
(按此顺序)LIB_B
也依赖于LIB_C
那么,扁平型依赖项顺序将如下所示:
LIB_A
LIB_D
LIB_B
LIB_C
这可以确保 LIB_A
和 LIB_B
都可以替换 LIB_C
;并且 LIB_D
的优先级仍高于 LIB_B
,因为 LIB_A
(依赖前者)的优先级高于 LIB_B
。
如需详细了解如何合并来自不同项目来源/依赖项的清单,请参阅合并多个清单文件。
查看模块依赖项
一些直接依赖项可能具有自己的依赖项。此类依赖项称为“传递依赖项”。Gradle 将会自动为您收集并添加这些传递依赖项,无需您手动逐一加以声明。 Android Plugin for Gradle 提供了一项任务,用来列出 Gradle 为给定模块解析的依赖项。
对于每个模块,报告还会根据 build 变体、测试源代码集和类路径对依赖项进行分组。下面是一个应用模块的依赖项示例报告,其中按该模块的调试 build 变体的运行时类路径和该模块的插桩测试源代码集的编译类路径对依赖项进行了分组。
debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...
debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...
如需运行该任务,请按以下步骤操作:
- 依次选择 View > Tool Windows > Gradle(或点击工具窗口栏中的 Gradle 图标
)。
- 依次展开 AppName > Tasks > android,然后双击 androidDependencies。Gradle 执行该任务后,系统应该会打开 Run 窗口以显示输出。
如需详细了解如何管理 Gradle 中的依赖项,请参阅 Gradle 用户指南中的依赖项管理基础知识。
修复依赖项解析错误
当您向应用项目添加多个依赖项时,这些直接和传递依赖项可能会相互冲突。Android Gradle 插件会尝试妥善解决这些冲突,但有些冲突可能会导致编译时或运行时错误。
为帮助您调查是哪些依赖项导致了错误,请检查应用的依赖项树,从中查找出现了多次或存在版本冲突的依赖项。
如果无法轻松识别重复的依赖项,请尝试使用 Android Studio 的界面搜索包含重复类的依赖项,具体操作步骤如下:
- 从菜单栏中依次选择 Navigate > Class。
- 在弹出式搜索对话框中,确保已勾选 Include non-project items 旁边的框。
- 输入 build 错误中出现的类的名称。
- 检查结果以查找包含该类的依赖项。
下面几部分介绍您可能会遇到的不同类型的依赖项解析错误及其修复方法。
修复重复类错误
如果某个类多次出现在运行时类路径上,您会收到一条与以下内容类似的错误:
Program type already present com.example.MyClass
此错误通常是下列其中一种情况所致:
- 二进制文件依赖项包含一个库,该库也作为直接依赖项包含在您的应用中。例如,您的应用声明直接依赖于库 A 和库 B,但库 A 已在其二进制文件中包含库 B。
- 如需解决此问题,请取消将库 B 作为直接依赖项。
- 您的应用的本地二进制文件依赖项和远程二进制文件依赖项是同一个库。
- 如需解决此问题,请移除其中一个二进制文件依赖项。
解决类路径之间的冲突
当 Gradle 解析编译类路径时,会先解析运行时类路径,然后使用所得结果确定应添加到编译类路径的依赖项版本。换句话说,运行时类路径决定了下游类路径上完全相同的依赖项所需的版本号。
应用的运行时类路径还决定了 Gradle 需要对应用的测试 APK 的运行时类路径中的匹配依赖项使用的版本号。图 1 说明了类路径的层次结构。
图 1. 出现在多个类路径中的依赖项的版本号必须根据此层次结构匹配。
例如,当应用使用 implementation
依赖项配置添加某个依赖项的一个版本,而库模块使用 runtimeOnly
配置添加该依赖项的另一个版本时,就可能发生多个类路径中出现同一依赖项的不同版本的冲突。
在解析对运行时和编译时类路径的依赖关系时,Android Gradle 插件 3.3.0 及更高版本会尝试自动解决某些下游版本冲突。例如,如果运行时类路径包含库 A 版本 2.0,而编译类路径包含库 A 版本 1.0,则插件会自动将对编译类路径的依赖关系更新为库 A 版本 2.0,以避免错误。
不过,如果运行时类路径包含库 A 版本 1.0,而编译类路径包含库 A 版本 2.0,插件不会将对编译类路径的依赖关系降级为库 A 版本 1.0,您仍会收到一条与以下内容类似的错误:
Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'. Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.
如需解决此问题,请执行以下某项操作:
- 将所需版本的依赖项作为
api
依赖项添加到库模块。也就是说,尽管只有库模块声明了相应依赖项,但应用模块同样能够访问其 API。 - 或者,您也可以同时在两个模块中声明相应依赖项,但应确保两个模块使用的依赖项版本相同。不妨考虑配置项目全局属性,以确保每个依赖项的版本在整个项目中保持一致。
应用自定义构建逻辑
本部分介绍的高级主题在您要扩展 Android Gradle 插件或编写自己的插件时很有用。
向自定义逻辑发布变体依赖项
库可以包含其他项目或子项目可能要使用的功能。发布库是向其消费者提供库的过程。库可以控制其消费者在编译时和运行时可访问的依赖项。
有两种不同的配置,它们包含每个类路径的传递依赖项,消费者为了使用相应库而必须使用这些依赖项,具体说明如下:
variant_nameApiElements
:此配置包含编译时消费者可使用的传递依赖项。variant_nameRuntimeElements
:此配置包含消费者在运行时可使用的传递依赖项。
如需详细了解不同配置之间的关系,请参阅 Java 库插件配置。
自定义依赖项解析策略
一个项目可能会依赖于同一个库的两个不同版本,这样会导致依赖项冲突。例如,如果您的项目依赖于模块 A 的版本 1 和模块 B 的版本 2,而模块 A 以传递方式依赖于模块 B 的版本 3,则会出现依赖项版本冲突。
为了解决此冲突,Android Gradle 插件使用以下依赖项解析策略:当插件检测到依赖项关系图中存在同一模块的不同版本时,默认情况下,它会选择版本号最高的一个。
不过,此策略可能并不总是如您所愿。如需自定义依赖项解析策略,请使用以下配置解析任务所需的特定变体依赖项:
variant_nameCompileClasspath
:此配置包含适用于给定变体编译类路径的解析策略。variant_nameRuntimeClasspath
:此配置包含适用于给定变体运行时类路径的解析策略。
Android Gradle 插件包含可用于访问每个变体的配置对象的 getter。因此,您可以使用变体 API 查询依赖项解析,如以下示例所示:
Groovy
android { applicationVariants.all { variant -> // Return compile configuration objects of a variant. variant.getCompileConfiguration().resolutionStrategy { // Use Gradle's ResolutionStrategy API // to customize how this variant resolves dependencies. ... } // Return runtime configuration objects of a variant. variant.getRuntimeConfiguration().resolutionStrategy { ... } // Return annotation processor configuration of a variant. variant.getAnnotationProcessorConfiguration().resolutionStrategy { ... } } }
Kotlin
android { applicationVariants.all { // Return compile configuration objects of a variant. compileConfiguration.resolutionStrategy { // Use Gradle's ResolutionStrategy API // to customize how this variant resolves dependencies. ... } // Return runtime configuration objects of a variant. runtimeConfiguration.resolutionStrategy { ... } // Return annotation processor configuration of a variant. annotationProcessorConfiguration.resolutionStrategy { ... } } }
Play 管理中心的依赖项信息
使用 AGP 4.0.0 及更高版本构建应用时,该插件包含描述已编译到应用中的库依赖项的元数据。上传应用时,Play 管理中心会检查此元数据,以便为您提供有关应用使用的 SDK 和依赖项的已知问题提醒,在某些情况下还会提供解决这些问题的切实可行的反馈。
数据经过压缩,并由 Google Play 签名密钥加密,然后存储在您的发布应用的签名分块中。我们建议您保留此依赖项文件,以提供安全的良好用户体验。不过,如果您不希望分享这些信息,可以通过在模块的 build.gradle
文件中添加以下 dependenciesInfo
代码块来选择取消分享:
android {
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
// Disables dependency metadata when building Android App Bundles.
includeInBundle = false
}
}
如需详细了解我们的政策以及依赖项可能存在的问题,请参阅有关在应用中使用第三方 SDK 的支持页面。
SDK 数据分析
对于已被作者在 Google Play SDK 索引中标记为过时的公共 SDK,Android Studio 会在 build.gradle
文件和“Project Structure”对话框中显示 lint 警告。您可据此更新这些依赖项,因为如果继续使用过时的版本,您日后可能会无法将内容发布到 Google Play 管理中心。