Android Gradle 插件 (AGP) 是官方的 Android 应用构建系统。它支持编译许多不同类型的源代码,以及将其链接到可在实体 Android 设备或模拟器上运行的应用中。AGP 包含插件扩展点,用于控制 build 输入并通过可与标准 build 任务集成的新步骤扩展其功能。
Gradle build 基础知识
本指南未涵盖整个 Gradle 构建系统。不过,它涵盖了与我们的 API 集成所需的最基本的概念。该指南还链接到了主 Gradle 文档,以便您进一步了解相关信息。
我们假定您对 Gradle 的工作原理已有基本了解,包括如何配置项目、修改 build 文件、应用插件以及运行任务。如需了解关于 AGP 的 Gradle 基础知识,我们建议您查看配置 build。如需了解用于自定义 Gradle 插件的通用框架,请参阅开发自定义 Gradle 插件。
Gradle 延迟类型术语表
Gradle 提供多种类型,它们可表现出“延迟”行为,或者帮助将繁重的计算或 Task
创建推迟到 build 的后续阶段。这些类型是许多 Gradle 和 AGP API 的核心。以下列表包含延迟执行涉及的主要 Gradle 类型及其主要方法。
<dl style="box-sizing: inherit; margin: 0px; padding: 0px; color: rgb(32, 33, 36); font-family: "Google Sans Text", "Noto Sans", "Noto Sans JP", "Noto Sans KR", "Noto Naskh Arabic", "Noto Sans Thai", "Noto Sans Hebrew", "Noto Sans Bengali", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">
<dt style="box-sizing: inherit; font: 700 16px/24px var(--devsite-primary-font-family); margin: 16px 0px;">Provider<T>
</dt>
<dd style="box-sizing: inherit; margin: 16px 0px; padding: 0px 0px 0px 40px;">提供类型为 T
的值(其中“T”表示任意类型),该值可以在执行阶段使用 get()
读取,也可以使用 map()
、flatMap()
和 zip()
方法转换为新的 Provider<S>
(其中“S”表示其他类型)。请注意,切勿在配置阶段调用 get()
。
-
map()
:接受 lambda 并生成类型为S
的Provider
,即Provider<S>
。map()
的 lambda 参数会采用值T
并生成值S
。系统不会立即执行 lambda,而是会推迟到在生成的Provider<S>
上调用get()
时执行,从而让整个链条变得延迟。 -
flatMap()
:同样会接受 lambda 并生成Provider<S>
,但 lambda 会采用值T
并生成Provider<S>
(而不是直接生成值S
)。如果在配置时无法确定 S 且您只能获得Provider<S>
,请使用 flatMap()。实际上,如果您使用了map()
并且最终生成的类型为Provider<Provider<S>>
,则可能表示您本该使用flatMap()
。 -
zip()
:可让您结合两个Provider
实例以生成新的Provider
,其值是使用将两个输入Providers
实例的值结合的函数计算得出的。
</dd>
<dt style="box-sizing: inherit; font: 700 16px/24px var(--devsite-primary-font-family); margin: 16px 0px;">Property<T>
</dt>
<dd style="box-sizing: inherit; margin: 16px 0px; padding: 0px 0px 0px 40px;">实现 Provider<T>
,这样会提供类型为 T
的值。与只读的 Provider<T>
不同,您还可以为 Property<T>
设置值。为其设置值的方法有两种:
- 在可行的情况下直接设置类型为
T
的值,而无需推迟计算。 - 将另一个
Provider<T>
设置为Property<T>
的值的来源。在这种情况下,值T
只会在系统调用Property.get()
时具体化。
</dd>
<dt style="box-sizing: inherit; font: 700 16px/24px var(--devsite-primary-font-family); margin: 16px 0px;">TaskProvider
</dt>
<dd style="box-sizing: inherit; margin: 16px 0px; padding: 0px 0px 0px 40px;">实现 Provider<Task>
。如需生成 TaskProvider
,请使用 tasks.register()
,而不是 tasks.create()
,以确保任务只在需要时才会延迟实例化。在 Task
创建之前,您可以使用 flatMap()
来访问该 Task
的输出,如果您想将此输出用作其他 Task
实例的输入,这会很实用。</dd>
</dl>
如要以延迟方式设置任务的输入和输出,提供程序及其转换方法至关重要,也就是说,无需预先创建所有任务并解析值。
提供程序还携带有任务依赖项信息。当您通过转换一个 Task
的输出来创建 Provider
时,该 Task
会成为相应 Provider
的隐式依赖项,无论 Provider
的值在何时进行解析(例如当另一个 Task
需要它时),系统都要会创建并运行该 Task。
下面的示例展示了如何注册 GitVersionTask
和 ManifestProducerTask
这两个任务,同时将 Task
实例的创建推迟到实际需要时。ManifestProducerTask
输入值设置成了从 GitVersionTask
的输出获取的 Provider
,因此 ManifestProducerTask
隐式依赖于 GitVersionTask
。
// Register a task lazily to get its TaskProvider.
val gitVersionProvider: TaskProvider =
project.tasks.register("gitVersionProvider", GitVersionTask::class.java) {
it.gitVersionOutputFile.set(
File(project.buildDir, "intermediates/gitVersionProvider/output")
)
}
...
/**
* Register another task in the configuration block (also executed lazily,
* only if the task is required).
*/
val manifestProducer =
project.tasks.register(variant.name + "ManifestProducer", ManifestProducerTask::class.java) {
/**
* Connect this task's input (gitInfoFile) to the output of
* gitVersionProvider.
*/
it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
}
这两个任务只会在被明确请求时才会执行。这种请求会发生在 Gradle 调用的过程中,例如,当您运行 ./gradlew debugManifestProducer
时,或者当您将 ManifestProducerTask
的输出关联到其他某些任务并且必须使用其值时。
尽管您将编写会使用输入和/或生成输出的自定义任务,但 AGP 不直接提供对其任务的公开访问权限。这些权限属于实现细节,每个版本都不一样。不过,AGP 会提供 Variant API 及对其任务输出的访问权限,或者提供可供您读取和转换的 build 工件。如需了解详情,请参阅本文档的 Variant API、工件和任务部分。
Gradle build 阶段
项目构建本身是一个复杂且耗费资源的过程,并且涉及各种功能,例如任务配置规避、更新检查和配置缓存功能,这些功能有助于最大程度减少花在可重现或非必要计算上的时间。
若要应用其中某些优化功能,Gradle 脚本和插件在以下每个不同的 Gradle build 阶段都必须遵循严格的规则:初始化、配置和执行。在本指南中,我们将重点介绍配置阶段和执行阶段。如需详细了解所有阶段,请参阅 Gradle build 生命周期指南。
配置阶段
在配置阶段,系统会评估 build 涉及到的所有项目的 build 脚本、应用插件并解析 build 依赖项。此阶段应该用来使用 DSL 对象配置 build,以及以延迟方式注册任务及其输入。
由于配置阶段总是在运行,因此无论系统请求运行哪个任务,都务必让该阶段保持精简,并对所有计算进行限制,防止其依赖于输入而不是 build 脚本本身。也就是说,您不应执行外部程序或从网络中读取内容,也不应执行可以作为合适的 Task
实例推迟到执行阶段的长时间计算。
注意:使用即将推出的配置缓存功能,此阶段的结果将被缓存,以供后续运行,但前提是要特别注意让构建系统知道所有动态输入,例如文件读取或对环境变量的访问。