Gradle 插件

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 并生成类型为 SProvider,即 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。

下面的示例展示了如何注册 GitVersionTaskManifestProducerTask 这两个任务,同时将 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 实例推迟到执行阶段的长时间计算。

注意:使用即将推出的配置缓存功能,此阶段的结果将被缓存,以供后续运行,但前提是要特别注意让构建系统知道所有动态输入,例如文件读取或对环境变量的访问。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容