如何在 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 脚本中应用我的插件并配置具有适当输入的任务。当前未执行任务。
想法和笔记:
我在创建任务时在插件应用函数中使用了 create
而不是 register
。我的理解是,通过使用 create,我是在说“嘿,我想创建一个任务,我希望构建立即知道它”,而不是“嘿,这是一个任务定义,但是一旦它被实际调用就让它延迟加载”在实施端
我将 ReleaseManager
的实现作为单独的函数移到了插件 class 中,并在任务创建闭包中调用了这些函数。这样可行。据我了解,这是因为在构建配置阶段,其中定义的任何内容都是 运行。如果我愿意,我可以使用 doFirst
或 doLast
闭包将其推迟到执行阶段。
我的直觉是,我已经创建了一个任务并确保构建现在立即知道它,但至少在执行阶段之前它没有执行任务的计划并且需要一个触发器。该触发器是直接调用任务还是任务取决于将在执行阶段 运行 执行的任务。
如有任何帮助,我们将不胜感激。如果需要,很乐意提供任何其他信息。
我不太确定 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 社区认为这是一种冗余。
好的,所以我一直在努力让这个正常工作,我只想编写我的测试并将它推送到 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 脚本中应用我的插件并配置具有适当输入的任务。当前未执行任务。
想法和笔记:
我在创建任务时在插件应用函数中使用了
create
而不是register
。我的理解是,通过使用 create,我是在说“嘿,我想创建一个任务,我希望构建立即知道它”,而不是“嘿,这是一个任务定义,但是一旦它被实际调用就让它延迟加载”在实施端我将
ReleaseManager
的实现作为单独的函数移到了插件 class 中,并在任务创建闭包中调用了这些函数。这样可行。据我了解,这是因为在构建配置阶段,其中定义的任何内容都是 运行。如果我愿意,我可以使用doFirst
或doLast
闭包将其推迟到执行阶段。我的直觉是,我已经创建了一个任务并确保构建现在立即知道它,但至少在执行阶段之前它没有执行任务的计划并且需要一个触发器。该触发器是直接调用任务还是任务取决于将在执行阶段 运行 执行的任务。
如有任何帮助,我们将不胜感激。如果需要,很乐意提供任何其他信息。
我不太确定 this 是否对您有帮助。
你试过了吗
myPluginTask.configure {
mustRunAfter TASKNAME
}
我环顾四周,
下面的一位用户提供了深刻的见解
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 社区认为这是一种冗余。