如何在 Android 项目配置阶段在 Gradle 插件中 运行 自定义 Gradle 任务?

How to Run Custom Gradle Task In Gradle Plugin During Android Project Configuration Phase?

好的,所以我一直在努力让这个正常工作,我只想编写我的测试并将它推送到 Maven,这样我的站会更新就不会日复一日地更新了。

问题陈述: 我有多个 android 项目都需要相同的预配置。这包括声明 maven 存储库、设置 versionCodes 和 versionNames 以及其他 misc 配置项。将相同的块复制并粘贴到每个项目中或放置在本地 common.gradle 文件中,然后在项目级别 build.gradle 配置阶段应用和调用。

我的解决方案:将所有这些通用逻辑提取到一个独立的gradle插件中,让每个项目build.gradle文件应用这个插件来接收这些配置事件。

我创建了一个独立的插件,对插件进行了覆盖,它看起来像这样:

class CommonManager: Plugin<Project> {
    override fun apply(target: Project) {
        println("APPLY FUNCTION HAS BEEN ENTERED")
        target.tasks.create("myPluginTask", ReleaseManager::class.java)
    }

ReleaseManager class 是一个扩展 DefaultTask 并创建任务到 运行 的 class。这是 gradle 文档中推荐的内容,从可测试性/可重用性的角度来看它是有意义的,class 看起来像这样:

abstract class ReleaseManager: DefaultTask() {
    @get:Input
    abstract val versionHistoryPath: Property<String>

    @TaskAction
    fun configureVersionsAndReleaseMeta() { // do work... }

根据我阅读过的文档和我浏览过的其他示例项目,这是正确设置的。我使用 java-library 而不是 java 构建插件只是为了让本地 .jar 文件指向我的 android 项目以进行快速测试。这些 build.gradle 文件之一的示例如下所示:

buildscript {

    repositories {
        google()
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }

    dependencies {
        // misc dependencies ...
        classpath files("libs/MyCustomPlugin-1.0-SNAPSHOT.jar")
    }
}


apply plugin: "com.myplugin.common"

myPluginTask {
    versionHistoryPath.set("sdk/version_history.txt")
}

subprojects {
    apply plugin: 'maven-publish'
    apply plugin: 'com.jfrog.artifactory'
    group = 'org.jfrog.test.gradle.publish'
}

我创建了对 .jar 的依赖并应用插件,然后使用 属性 需要 运行 配置任务。但是,在日志输出 > Configure project 的配置阶段,任务从不 运行s 我在插件日志中看到来自应用函数的打印语句,但任务中没有输出或配置发生 class 我定义的。如果我单击 myPluginTaks{} 配置定义旁边的播放箭头,它实际上 运行 很好。此时,我知道我正确地指向了 .jar,我可以访问我在我的插件 class 中创建的任务,并且我可以分别设置它的 属性。我刚开始使用 gradle 进行此类自定义工作,想了解我做错了什么。让我概述一下我的思考过程和我尝试过的调试步骤。

我的“Bug”声明: 我希望任务 "myPluginTask" 在我的 build.gradle 脚本中应用我的插件并配置具有适当输入的任务。当前未执行任务。

想法和笔记:

如有任何帮助,我们将不胜感激。如果需要,很乐意提供任何其他信息。

我不太确定 this 是否对您有帮助。

你试过了吗

myPluginTask.configure {
   mustRunAfter TASKNAME
}

我环顾四周, 也可能有帮助。

下面的一位用户提供了深刻的见解 ,帮助我找到了解决方案。此时我对 Gradle 也有了更好的理解,可以更好地表达我的问题。

TLDR;我的直觉是正确的。我已经成功创建了一个任务,但没有提供触发该任务的方法。您可以根据目标项目提供的任务来执行此操作。

重申一下,我的插件 class 如下所示:

class CommonManager: Plugin<Project> {
    override fun apply(target: Project) {
        println("APPLY FUNCTION HAS BEEN ENTERED")
        target.tasks.create("myPluginTask", ReleaseManager::class.java)
    }

我的模块级别 build.gradle 应用插件的文件具有以下内容:

apply plugin: "com.myplugin.common"
apply plugin: "com.android.library"

apply 函数将在我的插件中触发,任务将被创建。但是,它不会 运行。为此,我需要依赖目标构建中的另一个任务作为触发器。这实际上看起来像下面这样:

class CommonManager: Plugin<Project> {
    override fun apply(target: Project) {
        println("APPLY FUNCTION HAS BEEN ENTERED")
        target.tasks.create("myPluginTask", ReleaseManager::class.java) { task ->
            // Have target project create a dependency between its task and mine
            target.tasks.findByName("preBuild").dependsOn(task)
    }

“preBuild”是 android 插件提供的任务。在我的例子中 com.android.library 这导致了第二个问题。在构建我的项目时,插件会抛出一个错误,指出“preBuild”不是一个已定义的任务。起初我以为我无法引用 android 库提供的任务,但后来它击中了我。如果您查看我上面的模块 build.gradle 文件的代码块,您会注意到我首先定义了我的通用插件。这意味着在我的插件应用块触发时,插件不知道这个任务,因为 android 插件还没有被应用。

您可以先定义 android 插件并记录定义顺序很重要,但这不是一个实用的解决方案。但是,您可以做的是像这样在目标项目上实施 afterEvaluate 闭包:

class CommonManager: Plugin<Project> {
    override fun apply(target: Project) {
        println("APPLY FUNCTION HAS BEEN ENTERED")
        target.tasks.create("myPluginTask", ReleaseManager::class.java) { task ->
            target.afterEvaluate {
                // Have target project create a dependency between its task and mine
                target.tasks.findByName("preBuild").dependsOn(task)
            }
    }

这将等待模块 build.gradle 文件的评估完成。因此,一旦我的插件应用块被触发,我的插件就会知道“preBuild”任务,因为在项目评估期间应用了 android 插件。

额外提示:我正在使用 create 在插件中创建我的任务。如果您使用的是 register,则不需要 afterEvaluate 闭包。如果您定义一个,如果 运行ning gradle 7.0 或更高版本,插件将抛出 运行time 错误。 gradle 社区认为这是一种冗余。