Gradle中Task详解

2,408 阅读4分钟

什么是Task

Task 在 Android Gradle 的构建系统中是一个非常重要的角色,Gradle 的构建工作都是由一系列 Task 组合完成的。一个 Project 里面可以包含很多个 Task 。Task 可以理解为一个执行体,在 Project 的视角下,也可以看作是一个原子性的操作。本篇文章我会先带大家从 gradle-api 源码的角度来看Task所属位置,之后再介绍 Task 的详细用法。

源码视角下的Task

一个 Android 项目都会有一个 rootProject (在根目录),每一个 module 也会有自己的 Project ,前面说了,一个 Project 会包含很多个 Task,具体交由 Project 的 TaskContainer 管理,我们具体看源码:

public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
    //...省略无关代码

    TaskContainer getTasks();
    
}

通过getTasks()方法获取TaskContainer的实例,TaskContainer 负责管理所有的 Task 实例。

Project接口的具体实现类 DefaultProject 在构造方法里会初始化 TaskContainer ,如下,通过 services 获取TaskContainer的实例:

    public DefaultProject(String name, @Nullable ProjectInternal parent, File projectDir, File buildFile, ScriptSource buildScriptSource, GradleInternal gradle, ServiceRegistryFactory serviceRegistryFactory, ClassLoaderScope selfClassLoaderScope, ClassLoaderScope baseClassLoaderScope) {
        //...省略无关代码
        
        this.services = serviceRegistryFactory.createFor(this);
        this.taskContainer = (TaskContainerInternal)this.services.get(TaskContainerInternal.class);
    }

我们具体看 TaskContainer 源码:

public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task> {
    @Nullable
    Task findByPath(String var1);

    Task getByPath(String var1) throws UnknownTaskException;

    Task create(Map<String, ?> var1) throws InvalidUserDataException;

    Task create(Map<String, ?> var1, Closure var2) throws InvalidUserDataException;

    Task create(String var1, Closure var2) throws InvalidUserDataException;

    Task create(String var1) throws InvalidUserDataException;

    <T extends Task> T create(String var1, Class<T> var2) throws InvalidUserDataException;

    @Incubating
    <T extends Task> T create(String var1, Class<T> var2, Object... var3) throws InvalidUserDataException;

    <T extends Task> T create(String var1, Class<T> var2, Action<? super T> var3) throws InvalidUserDataException;

    TaskProvider<Task> register(String var1, Action<? super Task> var2) throws InvalidUserDataException;

    <T extends Task> TaskProvider<T> register(String var1, Class<T> var2, Action<? super T> var3) throws InvalidUserDataException;

    <T extends Task> TaskProvider<T> register(String var1, Class<T> var2) throws InvalidUserDataException;

    <T extends Task> TaskProvider<T> register(String var1, Class<T> var2, Object... var3) throws InvalidUserDataException;

    TaskProvider<Task> register(String var1) throws InvalidUserDataException;

    Task replace(String var1);

    <T extends Task> T replace(String var1, Class<T> var2);
}

TaskContainer 有一系列的方法,首先是create()系列方法,都是用来创建 Task 的,接着是 register() 系列方法,此方法会定义一个Task,但是是在需要时才会创建。findByPath()/getByPath()方法是根据路径查找Task。

接着我们看 Task 的具体定义:

public interface Task extends Comparable<Task>, ExtensionAware {
    //...省略

    @Internal
    String getName();

    @Internal
    Project getProject();

    @Internal
    List<Action<? super Task>> getActions();

    void setActions(List<Action<? super Task>> var1);

    @Internal
    TaskDependency getTaskDependencies();

    @Internal
    Set<Object> getDependsOn();

    void setDependsOn(Iterable<?> var1);

    Task dependsOn(Object... var1);

    @Internal
    String getPath();

    Task doFirst(Action<? super Task> var1);

    Task doFirst(Closure var1);

    @Incubating
    Task doFirst(String var1, Action<? super Task> var2);

    Task doLast(Action<? super Task> var1);

    @Incubating
    Task doLast(String var1, Action<? super Task> var2);

    Task doLast(Closure var1);

    @Internal
    @Nullable
    String getGroup();

    void setGroup(@Nullable String var1);

    @Internal
    TaskInputs getInputs();

    @Internal
    TaskOutputs getOutputs();

    @Internal
    TaskDependency getMustRunAfter();

    Task finalizedBy(Object... var1);

    void setFinalizedBy(Iterable<?> var1);

    @Internal
    TaskDependency getFinalizedBy();
}

这里我省略了一些方法,留下一些重要的来讲解。

首先是 Action相关,执行一个 Task就是执行它的 所有 Action。 像源码里 doFirst、doLast 都会接收一个闭包,然后做为 Task的一个个 Action 来执行。doFirst、doLast系列方法,顾名思义,就是在 Task的最前面、最后面执行。

group系列方法用来给当前 Task 分组,看下图:

每一个task都会有分组,如果不指定默认在 other 分组里。

创建一个Task

task customTask {
    doLast {
        println '我是 customTask'
    }
}

你会看到,创建 task 好像是通过关键字来的,其实 "task" 是 Project 类的一个函数,它内部会委托TaskContainer调用create函数创建。customTask 是参数任务名字,第二个参数是一个闭包,在groovy语法里,如果最后一个参数是闭包的时候,可以放到括号外面,然后方法的括号可以省略,这样就成了我们上面的写法。

任务依赖

任务之间是有依赖关系的,这样可以控制哪些任务优先于哪些任务执行。比如Android的 install 任务一定依赖于 package 任务进行打包生成 apk。

我们通过 dependsOn 指定当前任务需要依赖的任务,如下:

task clean(type: Delete) {
    doFirst {
        println '开始clean'
    }
    delete rootProject.buildDir
}

task customTask(dependsOn: clean) {
    doLast {
        println '我是 customTask'
    }
}

我把 customTask 任务依赖于 clean 任务,则执行 clean 任务之前一定会先执行 customTask 任务,如下输出:

> Task :clean UP-TO-DATE
开始clean

> Task :customTask
我是 customTask

BUILD SUCCESSFUL in 0s

任务分组

任务是可以添加分组的,如果不添加,默认在other 分组里,如下是对任务添加一个分组:

def myTask = task customTask(dependsOn: clean) {
    doLast {
        println '我是 customTask'
    }
}
myTask.group = "custom"

我们点击 sync 同步后,会在Android Studio右边栏看到 custom 分组下的task: