添加构建依赖项
Android Studio中的Gradle构建系统可以轻松地将外部二进制文件或其他库模块作为依赖项包含在构建中。依赖项可以位于您的计算机上或远程存储库中,并且它们声明的任何传递依赖项也会自动包含在内。此页面描述了如何在Android项目中使用依赖项,包括特定于Gradle的Android插件的行为和配置的详细信息。有关Gradle依赖关系的更深入的概念指南,您还应该看到依赖关系管理的 Gradle指南 - 但请记住,您的Android项目必须仅使用 此页面上定义的依赖关系配置。
警告:指定依赖项时,不应使用动态版本号,例如'com.android.tools.build:gradle:3.+'
。使用此功能可能会导致意外的版本更新,并且难以解决版本差异。
依赖类型
要向项目添加依赖项,请指定依赖项配置,例如implementation
在文件dependencies
块中build.gradle
。
例如,build.gradle
app模块的以下文件包含三种不同类型的依赖项:
apply plugin: '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'
}
这些中的每一个都请求不同类型的库依赖,如下所示:
本地库模块依赖
实施项目(':mylibrary' )
此声明一有依赖性 的Android库模块名为“在MyLibrary”(此名称必须与定义的库名称相匹配include:
你的 文件)。构建应用程序时,构建系统会编译库模块并将生成的已编译内容打包到APK中。 settings.gradle
本地二进制依赖
实现fileTree (dir :'libs' ,include :[ '* .jar' ])
Gradle在项目module_name/libs/
目录中声明对JAR文件的依赖 (因为Gradle读取相对于build.gradle
文件的路径)。
或者,您可以指定单个文件,如下所示:
实现文件('libs / foo.jar' ,'libs / bar.jar' )
远程二进制依赖
实现'com.example.android:app-magic:12.3'
这实际上是以下的简写:
实现组:'com.example.android' ,名称:'app-magic' ,版本:'12 .3'
这声明了对“com.example.android”命名空间组内“app-magic”库12.3版的依赖性。
注意:像这样的远程依赖项要求您声明Gradle应该查找库的相应远程存储库。如果库本地不存在,Gradle会在构建需要时将其从远程站点中拉出(例如,当您单击“使用Gradle文件同步项目” 或运行构建时)。
依赖配置
在dependencies
块中,您可以使用几种不同的依赖关系配置之一声明库依赖关系(如上implementation
所示)。每个依赖项配置都为Gradle提供了有关如何使用依赖项的不同说明。下表描述了可用于Android项目中的依赖项的每个配置。该表还将这些配置与Android Gradle Plugin 3.0.0中已弃用的配置进行了比较。
新配置 | 弃用配置 | 行为 |
---|---|---|
implementation | compile | Gradle将依赖项添加到编译类路径,并将依赖项打包到构建输出。但是,当您的模块配置implementation 依赖项时,它让Gradle知道您不希望模块在编译时将依赖项泄漏给其他模块。也就是说,依赖性仅在运行时可用于其他模块。 使用这种依赖性配置,而不是 |
api | compile | Gradle将依赖项添加到编译类路径并构建输出。当一个模块包含一个api 依赖项时,它让Gradle知道该模块想要将该依赖项传递给其他模块,以便它们在运行时和编译时都可用。 此配置的行为就像 |
compileOnly | provided | Gradle仅将依赖项添加到编译类路径(即,它不会添加到构建输出中)。这在您创建Android模块时非常有用,并且在编译期间需要依赖项,但在运行时将其存在是可选的。
如果使用此配置,则库模块必须包含运行时条件以检查依赖项是否可用,然后正常更改其行为,以便在未提供时仍可正常运行。这有助于通过不添加不重要的瞬态依赖项来减小最终APK的大小。此配置的行为就像 |
runtimeOnly | apk | Gradle仅将依赖项添加到构建输出,以便在运行时使用。也就是说,它不会添加到编译类路径中。此配置的行为就像apk (现在已弃用)。 |
annotationProcessor | compile | 要添加对作为注释处理器的库的依赖关系,必须使用annotationProcessor 配置将其添加到注释处理器类路径 。这是因为使用此配置可以通过将编译类路径与注释处理器类路径分开来提高构建性能。如果Gradle在编译类路径上找到注释处理器,它将停用 编译避免,这会对构建时间产生负面影响(Gradle 5.0及更高版本忽略编译类路径上的注释处理器)。 Android Gradle Plugin假定依赖是一个注释处理器,如果它的JAR文件包含以下文件:。如果插件检测到编译类路径上的注释处理器,则会产生构建错误。 META-INF/services/javax.annotation.processing.Processor |
以上配置适用于项目的主要源集,该源集适用于所有构建变体。如果您只想为特定的构建变体源集或 测试源集声明依赖项,则必须将配置名称大写,并在其前面加上构建变量或测试源集的名称。
例如,要implementation
仅向您的“免费”产品风格添加依赖项(使用远程二进制依赖项),它看起来像这样:
dependencies {
freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
}
但是,如果要为组合了产品flavor 和构建类型的变体添加依赖项,则必须在configurations
块中初始化配置名称。以下示例runtimeOnly
向您的“freeDebug”构建变体添加依赖项(使用本地二进制依赖项):
configurations {
// Initializes a placeholder for the freeDebugRuntimeOnly dependency
// configuration.
freeDebugRuntimeOnly {}
}
dependencies {
freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
}
要implementation
为本地测试和检测测试添加依赖项,它看起来像这样:
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 'com.android.support.test.espresso:espresso-core:3.0.2'
}
但是,某些配置在这种情况下没有意义。例如,因为其他模块不能依赖androidTest
,所以如果使用androidTestApi
配置,则会收到以下警告:
警告:配置'androidTestApi'已过时,已被替换为 'androidTestImplementation'。
添加注释处理器
如果将注释处理器添加到编译类路径中,您将看到类似于以下内容的错误消息:
错误:现在必须显式声明注释处理器。
要解决此错误,请使用annotationProcessor
如下所示配置依赖项,将注释处理器添加到项目中:
dependencies { //将定义注释的库添加到仅编译类路径。 compileOnly'com.google.dagger :dagger:version-number ' //将注释处理器依赖项添加到注释处理器类路径。 annotationProcessor'com.google.dagger :dagger-compiler:version-number ' }
注意: Gradle 3.0.0+的Android插件不再支持插件。 android-apt
将参数传递给注释处理器
如果需要将参数传递给注释处理器,则可以使用AnnotationProcessorOptions
模块的构建配置中的块来执行此操作。例如,如果要将原始数据类型作为键值对传递,则可以使用该argument
属性,如下所示:
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
argument "key1", "value1"
argument "key2", "value2"
}
}
}
}
但是,使用Android Gradle插件3.2.0及更高版本时,需要使用Gradle CommandLineArgumentProvider
接口传递表示文件或目录的处理器参数 。
使用CommandLineArgumentProvider
允许您或注释处理器作者通过将增量构建属性类型注释 应用于每个参数来提高增量和缓存干净构建的正确性和性能。
例如,下面的类实现CommandLineArgumentProvider
并注释处理器的每个参数。该示例还使用Groovy语言语法,并直接包含在模块的build.gradle
文件中。
注意:通常,注释处理器作者提供此类或有关如何编写此类的说明。这是因为每个参数都需要指定正确的构建属性类型注释才能按预期工作。
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 {...}
创建实现的类之后CommandLineArgumentProvider
,需要使用annotationProcessorOptions.compilerArgumentProvider
属性初始化并将其传递给Android插件 ,如下所示。
// 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"))
}
}
}
}
要了解有关实现如何CommandLineArgumentProvider
帮助提高构建性能的更多信息,请阅读 缓存Java项目。
禁用注释处理器错误检查
如果您对包含您不需要的注释处理器的编译类路径具有依赖性,则可以通过将以下内容添加到build.gradle
文件来禁用错误检查。请记住,添加到编译类路径的注释处理器仍未添加到处理器类路径中。
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath false
}
}
}
}
如果在将项目的注释处理器迁移到处理器类路径后遇到问题,则可以通过设置includeCompileClasspath
为允许编译类路径上的注释处理器true
。但是,true
不建议将此属性设置为,并且将在Android插件的将来更新中删除执行此操作的选项。
排除传递依赖项
随着应用程序在范围内的增长,它可以包含许多依赖项,包括直接依赖项和传递依赖项(应用程序导入的库所依赖的库)。要排除不再需要的传递依赖项,可以使用exclude
以下给出的 关键字:
dependencies {
implementation('some-library') {
exclude group: 'com.example.imgtools', module: 'native'
}
}
从测试配置中排除传递依赖性
如果您需要从测试中排除某些传递依赖项,则上面显示的代码示例可能无法按预期工作。这是因为测试配置(例如androidTestImplementation
)扩展了模块的 implementation
配置。也就是说,implementation
当Gradle解析配置时,它始终包含依赖项。
因此,要从测试中排除传递依赖性,必须在执行时执行此操作,如下所示:
android.testVariants.all { variant ->
variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}
注意:您仍然可以exclude
在依赖项块中使用关键字,如“ 排除依赖项”部分中的原始代码示例所示, 以省略特定于测试配置但未包含在其他配置中的传递依赖项。
使用变体感知依赖关系管理
Android插件3.0.0及更高版本包含一个新的依赖机制,可以在使用库时自动匹配变体。这意味着应用程序的 debug
变体会自动使用库的debug
变体,依此类推。它在使用flavor时也有效 - 应用程序的freeDebug
变体将使用库的freeDebug
变体。
为了使插件准确匹配变体,您需要 为无法直接匹配的实例提供匹配的回退。考虑一下你的应用程序是否配置了一个名为“staging”的构建类型,但其中一个库依赖项却没有。当插件尝试构建应用程序的“暂存”版本时,它将不知道要使用的库版本,您将看到类似于以下内容的错误消息:
错误:无法解决:无法解析项目:mylibrary。 要求: 项目:app
解决与变体匹配相关的构建错误
该插件包含DSL元素,可帮助您控制Gradle应如何解决无法在应用程序和依赖项之间进行直接变体匹配的情况。请参阅下表以确定应使用哪个DSL属性来解决与变体感知依赖项匹配相关的某些构建错误。
构建错误的原因 | 解析度 |
---|---|
您的应用程序包含库依赖项不包含的构建类型。 例如,您的应用程序包含“暂存”构建类型,但依赖项仅包括“调试”和“发布”构建类型。 请注意,当库依赖项包含您的应用程序不包含的构建类型时,没有问题。那是因为插件根本不会从依赖项中请求构建类型。 | 使用 //在app的build.gradle文件中。 android { buildTypes { debug {} release {} staging { //指定当依赖项不包含//“staging”构建类型时//插件应该尝试使用的后备构建类型的排序列表。您可以指定尽可能多的回退,并且插件选择依赖项中可用的第一个构建类型。 matchingFallbacks = [ 'debug' ,'qa' ,'release' ] } } } |
对于应用程序及其库依赖项中存在的给定风味维度,您的应用程序包含库不包含的风格。 例如,您的应用程序及其库依赖项都包含“层”风格维度。但是,应用程序中的“层”维度包括“免费”和“付费”风格,但依赖项仅包括相同维度的“演示”和“付费”风格。 请注意,对于应用程序及其库依赖项中存在的给定风味维度,当库包含应用程序不包含的产品风格时,不会出现问题。那是因为插件根本不会从依赖中请求那种味道。
| 使用 //在app的build.gradle文件中。 android { defaultConfig { //不要在defaultConfig块中配置matchingFallbacks。//相反,您必须在// productFlavors块中为给定的产品flavor指定回退,如下所示。} flavorDimensions “一线” productFlavors { 支付{ 尺寸“一线” //因为依赖已经包括在了“支付”的味道//“梯队”的维度,你并不需要提供回退的列表为//了“付出“味道。 //指定插件//在依赖项的匹配维度//不包含“free”风格时应尝试使用的后备风格的排序列表。您可以根据需要指定多个//回退,并且插件会选择依赖项“层”维度中可用的第一个风格。 matchingFallbacks = [ 'demo' ,'trial' ] } } } |
库依赖项包括应用程序不具有的flavor大小。 例如,库依赖项包括“minApi”维度的风格,但您的应用程序仅包含“层”维度的风格。因此,当您想要构建应用程序的“freeDebug”版本时,该插件不知道是否使用依赖项的“minApi23Debug”或“minApi18Debug”版本。 请注意,当您的应用包含库依赖项不包含的flavor维度时,不会出现问题。那是因为插件只匹配依赖项中存在的维度。例如,如果依赖项不包含ABI的维度,则应用程序的“freeX86Debug”版本将仅使用依赖项的“freeDebug”版本。 |
//在app的build.gradle文件中。 android { defaultConfig { //指定插件应该尝试从给定维度使用的排序列表。以下告诉插件,当遇到//包含“minApi”维度的依赖项时,它应该选择//“minApi18”风格。您可以包含其他flavor名称,以便为维度提供//排序后备列表。 missingDimensionStrategy'minApi ' ,'minApi18' ,'minApi23' //您应该为本地依赖项中存在的每个维度指定missingDimensionStrategy属性,但不应在应用程序中。 missingDimensionStrategy “ABI” ,“86” ,“arm64” } flavorDimensions “一线” productFlavors { 免费{ 尺寸“一线” //可以覆盖在产品风味的默认选择通过配置其他missingDimensionStrategy财产//水平//为“ minApi“维度。 missingDimensionStrategy'minApi ' ,'minApi23' ,'minApi18' } 已付{} } } |
配置Wear OS应用程序依赖项
配置Wear OS模块的依赖关系类似于任何其他模块的依赖关系。也就是说,它们使用相同的依赖配置,例如implementation
和compileOnly
。
Wear模块还支持变体感知依赖关系管理。因此,如果您的基本应用程序模块依赖于Wear模块,则基本模块的每个变体都会使用Wear模块中的匹配变体。如果您要构建一个仅依赖于一个Wear模块的简单应用程序,其中模块配置与基本模块相同的变体,则需要wearApp
在基本模块的build.gradle
文件中指定配置,如下所示:
dependencies {
// If the main and Wear app modules have the same variants,
// variant-aware dependency management automatically matches
// variants of the main app module with that of the wear module.
wearApp project(':wearable')
}
如果您有多个Wear模块,并且您希望为每个应用程序风格指定不同的Wear模块,则可以使用flavorWearApp
配置执行此操作,如下所示(但是,您不能包含使用该wearApp
配置的其他依赖项):
dependencies {
paidWearApp project(':wear1')
demoWearApp project(':wear1')
freeWearApp project(':wear2')
}
远程存储库
当您的依赖项不是本地库或文件树时,Gradle将在文件repositories
块中指定的任何联机存储库中查找 build.gradle
文件。列出每个存储库的顺序决定了Gradle在每个项目依赖项中搜索存储库的顺序。例如,如果存储库A和B都具有依赖关系,并且您首先列出A,则Gradle将从存储库A下载依赖关系。
默认情况下,新的Android Studio项目将Google的Maven存储库和JCenter 指定 为项目顶级build.gradle
文件中的存储库位置,如下所示:
allprojects {
repositories {
google()
jcenter()
}
}
如果您想要Maven中央存储库中的内容,则添加 mavenCentral()
或使用本地存储库mavenLocal()
:
allprojects {
repositories {
google()
jcenter()
mavenCentral()
mavenLocal()
}
}
或者,您可以按如下方式声明特定的Maven或Ivy存储库:
allprojects {
repositories {
maven {
url "https://repo.example.com/maven2"
}
maven {
url "file://local/repo/"
}
ivy {
url "https://repo.example.com/ivy"
}
}
}