Gradle -自定义task

本文详细介绍了如何在Gradle中自定义任务,包括使用DefaultTask和@TaskAction注解创建自定义ZipTask,以及利用afterEvaluate钩子函数动态调整任务依赖。还展示了如何通过插件机制实现更灵活的项目构建。

1 了解task

task是gardle中最小的任务单元,任务之间可以进行复杂的操作(如动态创建任务,多任务间依赖调用等等)。gradle的执行其实就是由各种任务组合执行,来对项目进行构建的。

使用gradlew help命令,任何gradle项目都有一个该task,可以执行此命令观察taks执行的流程是否如预期。 可以使用工具查看,还可以通过 gradlew tasks 命令查看可运行任务。

使用gradlew tasks --all 命令查看所有任务。

使用gradlew A B 命令表示执行任务A和B,支持驼峰简写。

2 自定义Task 

在build.gradle中自定义任务:

task <任务名>{ .. },在Gradle5.x以上已经删除<<操作符这种写法。

{ ... }执行的是配置阶段的代码,执行阶段要处理的逻辑需要调用doFirstdoLast方法,在闭包中实现。doFirst{}表示任务执行开始时调用的方法,doLast{}表示任务执行结束调用的方法。

task A(dependsOn:[B]){ .. } 表示任务A依赖于任务B,那么B执行在A之前。

自定义的任务默认分组到other中。

(1)自定义类继承DefaultTask

在方法上使用@TaskAction注解,表示任务运行时调用的方法。 使用@Input表示对任务的输入参数。 使用@OutputFile表示任务输出文件。 使用inputs,outputs直接设置任务输入/输出项。 一个任务的输出项可以作为另一个任务的输入项 (隐式依赖关系)。

class ZipTask extends DefaultTask {
    @Input
    @Optional
  // 表示可选
    String from
    File out
    ZipTask() {

        outputs.upToDateWhen {
            false//  增量构建,每次都会开启,不会跳过任务,构造函数中调用(如果没有更新就不会去构建,设置false将会每次都去构建)
        }
    }
    @TaskAction
    void fun() {
        println " @TaskAction fun()"
        println from
        println out
        //文件进行操作
        //inputs.files.first()
        println inputs.files.singleFile    
        def inFile = inputs.files.singleFile 

        def file = outputs.files.singleFile 
        file.createNewFile()  // 创建文件
        file.text = inFile.text 
    }
}

task myTask(type: ZipTask) {    
    from = "a/b/c" // 输入
    out = file("test.txt") // 输出
    inputs.file file('build.gradle')   //输入文件的路径,这种写法不需要使用 @Input注解
    outputs.file file('test.txt')  //输出的路径
}

使用@TaskAction注解  相当于main()函数,在调用task ,则会自动调用内部有该注解的方法。

(2)下面使用task 完成以下任务

使用自定义任务,实现zip打包packageDebug输出的内容   

这里使用到内部的task Zip ,如何使用这个task 如下

task zip(type: Zip) {
    archiveName "outputs.zip"// 输出的文件名字
    destinationDir file("${buildDir}/custom")// 输出的文件存放的文件夹
    from "${buildDir}/outputs"// 输入的文件
}

好,现在我们是实现任务。

这里我们需要使用到afterEvaluate, afterEvaluate是一个钩子函数  会让闭包里面的内容 在编译结果后才会执行,看具体实现

afterEvaluate {
    println tasks.getByName("packageDebug")
    task zip(type: Zip) {
        archiveName "outputs2.zip"// 输出的文件名字
        destinationDir file("${buildDir}/custom")// 输出的文件存放的文件夹
        from tasks.getByName("packageDebug").outputs.files// 输入的文件
        tasks.getByName("packageDebug").outputs.files.each {
            println it
        }
    }
}

Gradle内部的其他钩子函数。

gradle.beforeProject {
    println "gradle.beforeProject"
}
gradle.afterProject {
    println "gradle.afterProject"
}
gradle.taskGraph.whenReady {  
    println "gradle.taskGraph.whenReady"
}
beforeEvaluate {
    // 在root无效
    println "beforeEvaluate"
}
afterEvaluate {
    println "afterEvaluate"
}

为什么会需要到这些钩子函数,这里我们要了解下gradle的运行阶段,如下图

1 初始化阶段 :

如 setting.gradle 的执行

2 配置阶段(最重要的阶段):

buildGradle 内部创建的是project,所以默认作用域是project.

gradle.beforeProject()这些gradle引用的每一个工程在配置阶段都会去调用这些方法

project.beforeEvaluate()方法 只会在当前工程配置阶段会被调用。由于作用域是project所以project可以去省略。

给gradle 设置监听

gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
    @Override
    void beforeEvaluate(Project project) {
        println "beforeEvaluate"
    }
    @Override
    void afterEvaluate(Project project, ProjectState state) {
        println "afterEvaluate"
    }
})
gradle.addBuildListener(new BuildListener() {
    @Override
    void buildStarted(Gradle gradle) {
    }
    @Override
    void settingsEvaluated(Settings settings) {
    }
    @Override
    void projectsLoaded(Gradle gradle) {
    }
    @Override
    void projectsEvaluated(Gradle gradle) {
    }
    @Override
    void buildFinished(BuildResult result) {
    }
})

3执行阶段 

 

3 脚本二进制插件(通过实现Plugin)

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project target) {
        println "MyPlugin apply"
        target.afterEvaluate {
            println target.tasks.getByName("packageDebug")
            target.task(type: Zip, "zipDebug") {
                archiveName "outputs4.zip"// 输出的文件名字
                destinationDir target.file("${target.buildDir}/custom")// 输出的文件存放的文件夹
                from target.tasks.getByName("packageDebug").outputs.files// 输入的文件
                target.tasks.getByName("packageDebug").outputs.files.each {
                    println it
                }
            }
        }
    }
}

apply 为入口函数跟,内部实现跟上面。当然这块代码也是可以写在java 工程中的

public class MyPlugin2 implements Plugin<Project> {

    @Override
    public void apply(Project target) {
        target.afterEvaluate(project -> {
            System.out.println(project.getTasks().getByName("packageDebug"));
            Map<String, Class<?>> type = new HashMap<>();
            type.put("type", Zip.class);
            Zip zipDebug2 = (Zip) target.task(type, "zipDebug2");
            zipDebug2.setArchiveName("outputs5.zip");
            zipDebug2.setDestinationDir(new File(target.getBuildDir().getAbsolutePath()+"/custom"));
            zipDebug2.from(target.getTasks().getByName("packageDebug").getOutputs().getFiles());
        });
    }
}

自定义Plugin结束后,只需要在buildgradle中进行配置

apply plugin: MyPlugin
apply plugin: MyPlugin2

 

 

Download https://mirrors.huaweicloud.com/gradle/gradle-8.13-bin.zip, took 13 s 233 ms Starting Gradle Daemon... Gradle Daemon started in 2 s 297 ms Download https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/plugin/compose/org.jetbrains.kotlin.plugin.compose.gradle.plugin/2.0.21/org.jetbrains.kotlin.plugin.compose.gradle.plugin-2.0.21.pom, took 10 s 698 ms Download https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/compose-compiler-gradle-plugin/2.0.21/compose-compiler-gradle-plugin-2.0.21.pom, took 728 ms Download https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/compose-compiler-gradle-plugin/2.0.21/compose-compiler-gradle-plugin-2.0.21.module, took 1 s 310 ms Download https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/compose-compiler-gradle-plugin/2.0.21/compose-compiler-gradle-plugin-2.0.21-gradle85.jar, took 2 s 273 ms Download https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-gradle-plugin-api/2.0.21/kotlin-gradle-plugin-api-2.0.21-gradle85.jar, took 9 s 867 ms > Task :prepareKotlinBuildScriptModel UP-TO-DATE Downloading https://services.gradle.org/distributions/gradle-8.13-src.zip (3.77 MB / 59.20 MB) 第一个https://mirrors.huaweicloud.com/gradle/gradle-8.13-bin.zip下载地址我在gradle-wrapper.properties文件中配置了distributionUrl=https\://mirrors.huaweicloud.com/gradle/gradle-8.13-bin.zip已经从国内镜像下载了 但是 > Task :prepareKotlinBuildScriptModel UP-TO-DATE Downloading https://services.gradle.org/distributions/gradle-8.13-src.zip (3.77 MB / 59.20 MB)这个还是从官方下载了,在哪里配置 我用的是android-studio-2025.1.2.13
09-05
Android Studio 2025.1.2.13 中,若已在 `gradle-wrapper.properties` 配置 `distributionUrl` 从国内镜像下载 `gradle-8.13-bin.zip`,要让 `gradle-8.13-src.zip` 也从国内镜像下载,可通过如下步骤操作: ### 修改 `gradle-wrapper.properties` 文件 `gradle-wrapper.properties` 文件里的 `distributionUrl` 主要用于配置 Gradle 二进制文件的下载地址。而源码包的下载地址,可通过自定义 Gradle 初始化脚本来配置。 ### 创建自定义 Gradle 初始化脚本 在项目根目录下创建一个新的 `.gradle` 文件夹(若不存在),接着在该文件夹里创建一个初始化脚本,例如 `init.gradle`。 ### 编辑 `init.gradle` 脚本 在 `init.gradle` 脚本中添加如下代码: ```groovy allprojects { repositories { // 移除默认的 Maven Central 仓库 removeIf { it instanceof org.gradle.api.artifacts.dsl.MavenArtifactRepository && it.url.toString().startsWith('https://repo.maven.apache.org/maven2') } // 添加腾讯云镜像仓库 maven { url 'https://mirrors.cloud.tencent.com/gradle' } } } ``` 上述代码的作用是移除默认的 Maven Central 仓库,然后添加腾讯云镜像仓库。这能让 Gradle 在下载依赖时优先采用腾讯云镜像。 ### 配置 Gradle 使用初始化脚本 在 `gradle.properties` 文件中添加如下配置: ```properties org.gradle.project.gradleInitScript=$rootDir/.gradle/init.gradle ``` 此配置可让 Gradle 在启动时加载自定义的初始化脚本。 ### 验证配置 完成上述配置后,重新同步 Gradle 项目,Gradle 就会尝试从配置的国内镜像下载 `gradle-8.13-src.zip`。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值