An overview of the

I started a new series. The goal of this series of learning Gradle is to thoroughly understand Gradle. The main goal is to make notes on your own understanding to prevent forgetting

Gradle Series (1) : Groovy learning

Gradle Learning series (2) : Gradle core decryption

Understand Gradle

Gradle is a can build tools, he can app compilation of packaging, but we learn Gradle can’t think of it as a tool to learn, when we take him as a tool to learn, our goal is to, can write, can configure script is OK, but the real demand is complex and changeful in the work, we will use, To understand why, we need to think of it as a programming framework, so that we can be more comfortable with complex requirements, right

Remember how we used Okhttp in a project

  • First Okhttp is written in the Java language, so you must understand Java syntax
  • Secondly, Okhttp defines a lot of apis for requesting the network, so I want to learn various APIS of Okhttp to meet our different needs

The same idea applies to Gradle

  • First of all, Gradle is written in Groovy, so we understand Groovy syntax
  • Secondly, Gradle defines its own API, so we need to learn Gradle’s API
  • Finally, Gradle has the concept of plug-ins. Different plug-ins complete different tasks. For example, we use Android plug-ins to package and compile Android, so we need to learn various apis defined by Android plug-ins

Finally, we need to master the basic language Groovy, then master Gradle API and its lifecycle, and finally master Android plugin API, so that we can write Gradle

Here is the Gradle API document, looking back to the original write Gradle script originally is to play Gradle API, this thought seems to be ok, not so hard to imagine, after all, are a framework to learn

Gradle basic components

Let’s take a look at the basic components of the Gradle framework

Let’s take a look at this diagram, which is a normal Android project. This project consists of three modules

Each compiled Project in Gradle is a Project (such as app, MyLibrary and myLibary2). Each Project should contain multiple tasks when it is built. For example, an Android APK compilation might include a Java compiled Task. JNI compiled Task, package generated APK Task, etc

How many tasks a Project contains is determined by plug-ins, which define and execute tasks. A plug-in can contain multiple tasks

Gradle is a framework, which is responsible for defining processes and rules, and the specific work is implemented through plug-ins (similar to Taobao and Taobao merchants, Taobao is responsible for making rules and processes, while Taobao merchants are responsible for real selling things), such as: compiling Java plug-ins, compiling Groovy plug-ins, compiling Android APP plug-ins

Now we know that a compiled Project is a Project, while a Protect is defined and executed by tasks at build time

Now how many projects are there in the picture above?

The answer is three

Each Libary and each App is a separate Project, each Project root directory. To have a build gradle, build. Gradle is Project build script

So this gradle Project contains 3 projects, and we can choose to compile each Project independently

  • CD go to the Project directory
  • Then execute the Gradle task (for example: Gradle assemble)

However, if you have 100 projects, do you need to compile 100 projects separately? Can you compile all 100 projects directly in the root directory?

Sure, just add build.gradle and setting.gradle to the root of the gradle project

  • The root directory of build.gradle is mainly used to configure other sub-projects, such as adding properties to other sub-projects
  • The root directory is setting.gradle, which tells gradle how many projects there are in the Project, as shown below

An introduction to Gradle commands

Gradle projects View project information

Execute this command to see how many subprojects the Project contains

Gradle Tasks View task information

Gradle project-path:tasks Check the tasks in a project. Project-path is the directory name, followed by a colon. In the root directory, you need to specify the path of the project you want to see

Gradle task-name Executes a task

Above we looked at all the tasks, now let’s look at executing one of them

Finally, there is a dependency between tasks. For example, assemble a Task depends on other tasks. If this Task is executed, other tasks it depends on need to execute assemble before the final output

Since tasks are dependent on each other, we can customize the Task to depend on the assemble Task, so when the assemble Task executes, our custom Task will be executed first

Gradle workflow

The Gralde workflow consists of three phases

Initialization phase

Initiliazation In the initialization phase, the main task is to create a Project hierarchy, create a Project object for each Project, the corresponding is to execute setting. Gradle, a setting. Gradle corresponds to a setting object, Gradle can call its methods directly from the Settings API document

The configuration phase

The next phase is the Configration phase, which mainly configures the build.gradle in each Project. Between the initialization phase and the configuration phase, we can add hooks, which are added through the API

After the Configration phase is completed, the entire build project and its internal Task relationships are determined. We can access through gradle getTaskGraph method, the corresponding class for TaskExecutionGraph TaskExecutionGraph API documentation

As we know, each Project is composed of multiple tasks, and each Task has a dependency relationship. In the Configuration stage, a directed graph will be established to describe the dependency relationship between tasks. A Hook can also be added here, and some operations can be performed after the directed graph is established

Each build.gradle corresponds to a Project object that is created during the initialization phase. Here is the Project API documentation

Execution phase

The last stage is the execution stage, this stage is mainly to execute the Task, here can also add Hook, when the Task is finished to do something

Add listener for Gradle build process

Add this code to setting.gradle

gradle.addBuildListener(new BuildListener() {
    @Override
    void buildStarted(Gradle gradle) {
        println'buildStarted'
    }

    @Override
    void settingsEvaluated(Settings settings) {
        println 'Settings evaluation completed (code execution completed in Settings. gradle)'
        println 'Here the project has not been initialized.'

    }

    @Override
    void projectsLoaded(Gradle gradle) {
        println 'Project structure loading completed (initialization phase completed)'
        println 'Initialization is complete, the initialization of the project is complete, and the root project can be accessed:' + gradle.rootProject
    }

    @Override
    void projectsEvaluated(Gradle gradle) {
        println 'All project evaluations completed (end of configuration phase)'

    }

    @Override
    void buildFinished(BuildResult result) {
        println 'Build over'}})Copy the code

Execute the Gradle assemble task

L- 96.FCG8WP- 1504.:gradle renxiaohui$ ./gradlew assemble
setting---- 1518204878.
setting --- homedir/Users/renxiaohui/.gradle/wrapper/dists/gradle5.41.-all/3221gyojl5jsh0helicew7rwx/gradle5.41.
setting --- userhomedir/Users/renxiaohui/.gradle
setting -----paraentnull
"hahah"The project structure has been loaded (the initialization phase is finished). The initialization phase has been completed. You can access root project: root Project'gradle'

> Configure project :app
gradle---- 1518204878.
gradle --- homedir/Users/renxiaohui/.gradle/wrapper/dists/gradle5.41.-all/3221gyojl5jsh0helicew7rwx/gradle5.41.
gradle --- userhomedir/Users/Renxiaohui /. Gradle gradle -----paraentnull All projects evaluated (configuration phase completed) >Task :app:Assemble BUILD SUCCESSFULin 5s
Copy the code

Hook point

Here we borrow the pictures from Gradle foundation build lifecycle and Hook technical article to show when to Hook the whole lifecycle

Gradle provides callbacks at all stages. It is important to be careful when adding listeners. Listeners should be added before the declaration cycle of the callback, usually in setting. Gradle

BeforeProject and beforeEvaluate methods are called at the same time, but beforeProject is called on all items and beforeEvaluate is called on the called Project

The same applies to afterProject and afterEvaluated

Gets the elapsed time of the build

In the setting. Add the following code to gradle, gradle. TaskGraph. BeforeTask this method will be before the Task invoke the callback

long beginOfSetting = System.currentTimeMillis()

gradle.projectsLoaded {
    println 'Initialization phase, time:' + (System.currentTimeMillis() - beginOfSetting) + 'ms'
}

def beginOfConfig
def configHasBegin = false
def beginOfProjectConfig = new HashMap()
gradle.beforeProject { project ->
    if(! configHasBegin) { configHasBegin =true
        beginOfConfig = System.currentTimeMillis()
    }
    beginOfProjectConfig.put(project, System.currentTimeMillis())
}
gradle.afterProject { project ->
    def begin = beginOfProjectConfig.get(project)
    println 'Configuration phase,' + project + 'Time:' + (System.currentTimeMillis() - begin) + 'ms'
}
def beginOfProjectExcute
gradle.taskGraph.whenReady {
    println 'Configuration phase, total time:' + (System.currentTimeMillis() - beginOfConfig) + 'ms'
    beginOfProjectExcute = System.currentTimeMillis()
}
gradle.taskGraph.beforeTask { task ->
    task.doFirst {
        task.ext.beginOfTask = System.currentTimeMillis()
    }
    task.doLast {
        println 'Execution phase,' + task + 'Time:' + (System.currentTimeMillis() - task.beginOfTask) + 'ms'
    }
}
gradle.buildFinished {
    println 'Execution phase, time:' + (System.currentTimeMillis() - beginOfProjectExcute) + 'ms'
}
Copy the code

Run gradle assemble

L- 96.FCG8WP- 1504.: Gradle renxiaohui$./ Gradlew assemble25ms

> Configure project :Configuration phase, root project'gradle'Time:78ms

> Configure project :App configuration phase, project':app'Time:19ms

> Configure project :Mylibrary configuration phase, project':mylibrary'Time:7ms

> Configure project :Mylibrary2 configuration phase, project':mylibrary2'Time:10Ms configuration phase, total time:391ms

> Task :app:PreBuild The execution phase, task':app:preBuild'Time:0ms

> Task :app:PreDebugBuild Execution phase, task':app:preDebugBuild'Time:0ms
....
Copy the code

When Gradle executes a script, it generates the corresponding instance. Gradle has three main types of objects, each of which corresponds to a script

  • Gradle object: Built when the project is initialized. The global singleton exists. This object is the only one
  • Project object: Each build.gradle is converted to a Project object
  • Settings object: Seeting.gradle is converted to a Seetings object

Gradle is an official document

Gradle Object API

Gradle object API Documentation See the above documentation for some possible apis

gradle.afterProject/gradle.beforeProject

These two methods are called after each Project completes execution, or before execution begins

Write the code in seeting.gradle


gradle.afterProject {
    println 'gradle. AfterProject calls'
}

gradle.beforeProject {
    println 'gradle. BeforeProject calls'
}
Copy the code

Perform. / gradlew clean

L- 96.FCG8WP- 1504.:gradle renxiaohui$./gradlew clean setting. Gradle starts initialization phase, time:3ms

> Configure project :Gradle. beforeProject calls Gradle. afterProject calls the configuration stage, root project'gradle'Time:43ms

> Configure project :App gradle.beforeProject calls com.aliyun.gradle Gradle --- 2006449733.
gradle --- homedir/Users/renxiaohui/.gradle/wrapper/dists/gradle5.41.-all/3221gyojl5jsh0helicew7rwx/gradle5.41.
gradle --- userhomedir/Users/Renxiaohui /.gradle gradle -----paraentnull com.aliyun.gradle Gradle. AfterProject calls the configuration stage, project':app'Time:19ms

> Configure project :Mylibrary Gradle. beforeProject calls Gradle. afterProject calls the configuration stage, project':mylibrary'Time:5ms

> Configure project :Mylibrary2 Gradle. beforeProject calls Gradle. afterProject calls the configuration stage, project':mylibrary2'Time:5Ms configuration phase, total time:115ms

> Task :Clean Execution phase, task':clean'Time:0ms

> Task :app:Clean Execution phase, task':app:clean'Time:0ms

> Task :mylibrary:Clean Execution phase, task':mylibrary:clean'Time:0ms

> Task :mylibrary2:Clean Execution phase, task':mylibrary2:clean'Time:0Ms execution phase, time:8ms
Copy the code

Gradle object other apis

API describe
TaskExecutionGraph getTaskGraph() Gets the diagram of tasks in Project
buildStarted When the build starts the callback
settingsEvaluated Call back when setting.gradle evaluation is complete
projectsLoaded The projects completion callback is created during the initialization phase
projectsEvaluated The configuration phase completes the callback
buildFinished Build completion callback
addBuildListener Adding a build listener

TaskExecutionGraph API is introduced

TaskExecutionGraph API documentation

API describe
addTaskExecutionGraphListener Add listeners to the task execution diagram
addTaskExecutionListener Add listeners to the execution of the task
whenReady Is called when the task execution diagram has been populated
beforeTask Is called before a task is executed
afterTask Is called when a task has completed
hasTask Query whether the task exists
getAllTasks Get all tasks
Set getDependencies(Task task) Returns the dependency of the parameter Task

Project introduction

Project the API documentation

Introduces some possible apis, see the documentation for details

API describe
getRootProject() Get the root Project
getRootDir Return to the root directory folder
getBuildDir Return to the build directory where all build products go
setBuildDir(File path) Setting the build folder
getParent() Gets the parent Project of this Project
getChildProjects Gets the immediate child Project of this Project
setProperty(String name, @Nullable Object value) Set properties for this Project
getProject() But the current Project object is available to access the properties and methods of the current Project
getAllprojects Returns a collection of the current Project and its child projects
allprojects(Closure configureClosure) Returns a collection of the current Project and its child projects into the closure
getSubprojects Returns all child projects under the current Project
subprojects(Closure configureClosure) Returns all child projects under the current Project to the closure
Task task(String name) Create a Task and add it to this Priject
getAllTasks(boolean recursive) If recursive is true then all tasks of the current Project and subprojects are returned; if false only all tasks of the current Project are returned
getTasksByName(String name, boolean recursive) Return Task by name, if recursive is true then the Task of the current Project and child projects, if false only the Task of the current Project
beforeEvaluate(Closure closure) Called before the Project evaluation
afterEvaluate(Closure closure); Called after project evaluation
hasProperty(String propertyName) Check whether this property exists
getProperties() Get all properties
findProperty(String propertyName); Returns the value of the property
dependencies(Closure configureClosure) Configure dependencies for Project
buildscript(Closure configureClosure) Configure the build script for Project
project(String path, Closure configureClosure) Get the Project instance based on the path and configure the Project in the closure
getTasks() Return all tasks in this Project

attribute

When we write Java code, when we encounter some methods used by many classes at the same time, we will extract this common method to Utils as a public method to use, and there will be the same problem in Gradle, so how to extract public methods in Gradle?

The first time you define an extra property, you need to use the prefix ext to indicate the extra property. When you define an extra property, you don’t need to use the prefix ext to access it again

Add a new property in local.properties

Take the sdK.api property from setting.gradle and set it to the gradle object. Then print the property just assigned to the Gradle object

def text(){
    Properties properties = new Properties()
    File propertyFile = new File(rootDir.getAbsolutePath() + "/local.properties")
    properties.load(propertyFile.newDataInputStream())

    gradle.ext.api = properties.getProperty('sdk.api')

    println(gradle.api)
}

text()
Copy the code

The output

Setting. gradle starts execution"hahah"
Copy the code

Next we define a class utils. Gradle as a public class that provides public methods for other build.gradle

// This method extracts the package name from androidmanifest.xml
def getxmlpackage(boolean x){
// Note 1 what is the name of the project?
    def file=new File(project.getProjectDir().getPath()+"/src/main/AndroidManifest.xml");
    def paser = new XmlParser().parse(file)
    return paser.@package
}
// Note 2: whose ext is this?
ext{
	// In addition to the assignment ext.xxx= XXX, there is the closure assignment
    getpackage = this.&getxmlpackage
}
Copy the code

Introduce utils. Gradle in app module MyLibrary module and myLibrary2 module build.gradle

apply  from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle". println(getpackage(true))
Copy the code

The output

> Configure project :App takes out the package name = com.renxh. Gradle configuration phase, project':app'Time:18ms

> Configure project :Mylibrary takes out a package named = com.renxh. Mylibrary configuration phase, project':mylibrary'Time:73ms

> Configure project :Mylibrary2 takes out a package named = com.renxh. Mylibrary2 configuration phase, project':mylibrary2'Time:59Ms configuration phase, total time:271ms

Copy the code

If you see the output, you should know the answers to comments 1 and 2 above

  • The project in comment 1 refers to the project whose utils. Gradle is loaded
  • Note 2 also states that whoever loads utils. Gradle loads properties for their Project

In this way, we can put some common functions in the utils. Gradle, and then set some ext properties for the project it loads

API for file manipulation

Locate the file

this.getText("utils.gradle")

def getText(String path) {
    try {
        // In contrast to the way new file needs to pass an absolute path,
        // file starts the search relative to the current project
        File mFile = file(path)
        println mFile.text
    } catch (GradleException e) {
        println e.toString()
        return null}}Copy the code

Copy files

When the assemble task is complete, rename the generated app-debug.apk to renxhui.apk, and copy to the project root without copying the release files

tasks.getByName("assemble") {
      it.doLast {
            copy {
                  // Copy both files and folders
                  // Here is to copy the apk directory generated under app moudle to
                  // Build directory under the root project
                  from file("build/outputs/apk")
                  into getRootDir().path+ "/apk/"

                  rename('app-debug.apk'.'renxhui.apk')
                  exclude { details ->
                          details.file.name.contains('release')}}}}Copy the code

The file tree

Walk through the build/outputs/apk folder and print out the name of each file

 fileTree("build/outputs/apk"){ freeTree ->
                freeTree.visit{fileTreeElement->
                      println "Traversal, file name ="+"$fileTreeElement.file.name"}}Copy the code

The output

Traversal, file name =release traversal, file name = app-releas-unsigned. apk traversal, file name =output.json traversal, file name =debug traversal, file name =output.json traversal, The file name is =app-debug.apkCopy the code

Dependencies dependencies

 dependencies {
   implementation('3.1' org. Hibernate: hibernate.) {
     // Use version 3.1 preferentially in case of version conflict
     force = true

     // Exclude specific dependencies
     exclude module: 'cglib' //by artifact name
     exclude group: 'org.jmock' //by group
     exclude group: 'org.unwanted'.module: 'iAmBuggy' //by both name and group

     // Disable dependency passing
     // Pass the dependency: A => B => C, B uses the dependency of C,
     // If A is dependent on B, then A can use B
     Dependencies in C used in // are turned on by default (true)
     transitive = false}}Copy the code

Task

Task is a data type in Gradle, which represents the work to be executed. Different plug-ins can add different tasks, and each Task should be associated with a Project. Task is an atomic execution unit of Gradle construction, and Gradle connects tasks to complete a specific construction Task

The Task API documentation

The Task of creating

Since a Task is associated with a Project, we use the Task (String name) method in Project to create it

Task myTask {configure closure} task myTask(myTask <==myTask)type: SomeType) 
task myTask(type: SomeType) { configure closure }
task myTask(dependsOn:SomeTask){configure closure}

task aa{
    println "ccc"
    doFirst{
       println "aaa"
    }

    doLast{
        println"bbb"}}Copy the code
  • A Task contains multiple actions. A Task has two functions, doLast and doFristdoLast: operations performed after the Task is executed, doFrist: operations performed before the Task is executed, and an Action is a closure

  • Task myTask(Type :Copy) creates a Task that inherits from Copy and is a Copy Task

  • When we use task myTask {configure closure}, this will cause Gradle to execute the closure after creating the task before returning it to the user. The code in parenthesis is just configuration code. It will be executed during configuration. It is not an Action. An Action is executed only when the Task is executed. For example, doLast and doFrist are two actions

  • The dependsOn attribute can be used when creating a Task, indicating that the current Task is dependent on the xx Task and that the xx Task must be executed before the current Task

  • DoLast has an equivalent operation called leftShift. LeftShift can be abbreviated to <<. This is just a syntactic sugar

myTask1.doLast {
    println "task1 doLast"
}

myTask1 << {
    println "task1 doLast<<"
}

myTask1.leftShift {
    println "task1 doLast leftShift"
}
Copy the code

Several ways to create a Task

task myTask1 {
    doLast {
        println "doLast in task1"
    }
}

task myTask2 << {
    println "doLast in task2"
}

// Use the project.task (String name) method
project.task("myTask3").doLast {
    println "doLast in task3"
}

// Use the taskContainer.create (String name) method
project.tasks.create("myTask4").doLast {
    println "doLast in task4"
}

project.tasks.create("myTask5") << {
    println "doLast in task5"
}
Copy the code

Description of the parameters for creating a Task

Parameter names describe The default value
name The name of the task Must not be null
type The task of the superclass The default value is org. Gradle. API. DefaultTask
overwrite Whether to replace task with the same name The default false
group Name of the group to which the task belongs null
description The description of the task null
dependsOn Task Set of dependent tasks There is no
constructorArgs Constructor parameter There is no
task myTask3(description: "This is the description of task3.".group: "myTaskGroup".dependsOn: [myTask1, myTask2], overwrite: true) << {
    println "doLast in task3, this is new task"
}
Copy the code
task aa{
    doFirst{
       println "aaa"
    }

    doLast{
        println"aa"
    }
}

task bb(dependsOn:'aa') {
    doFirst{
        println "bb"
    }

    doLast{
        println 'bb'}}Copy the code

The custom Task

class MyTask extends DefaultTask{

    String msg = "mmm";
    int age = 18;

    // Constructors must be identified with the @javax.inject.Inject annotation
    @javax.inject.Inject
    MyTask(){
    }

    @TaskAction
    void sayhello(){
        println "Hello $msg ! age is ${age}"}}Copy the code
  Task hello = project.task("hello2".type: MyTask)

        / / configuration task
        hello.configure {
            println("configure")

            msg = "123"
        }
Copy the code

To perform a Task

> Task :app:hello2
Hello 123 ! age is 18Execution phase, task':app:hello2'Time:0ms
Copy the code

The Task class diagram

class SayHelloTask extends DefaultTask {
    
    String msg = "default name";
    int age = 20

    @TaskAction
    void sayHello() {
        println "Hello $msg ! Age is ${age}"
    }

}

task test1 << {
    println "task test1 exec..."
}
task test2 << {
    println "task test2 exec..."
}
task test3 << {
    println "task test3 exec..."
}
task hello(type: SayHelloTask, group: "MyGroup")

// Configure the task,
hello.configure {
    println "hello task configure"
    msg = "hjy"
}

// Get the task name
println "task name is ${hello.getName()}"
// Obtain the group name of the task
println "task group is ${hello.getGroup()}"

// Set age = 70
hello.setProperty("age".70)
// Get the value of an attribute in the task
println "task msg is ${hello.property('msg')}"

// Set the dependent task so that the hello task is executed only after the test1 task is finished
hello.dependsOn(test1)
// Set the terminator task. After the hello task is executed, the test2 task will be executed
hello.finalizedBy(test2)

// If both task hello and task test3 are executed at the same time, the hello task will be executed only after test3 is finished
hello.setMustRunAfter([test3])

// The task is executed only after a certain condition is met
hello.setOnlyIf {
    // Task is executed only when age = 70, otherwise it is not executed
    return hello.property("age") = =70
}

Copy the code

The TaskContainer interface is resolved

/ / search task
findByPath(path: String): Task 
getByPath(path: String): Task
getByName(name: String): Task
withType(type: Class): TaskCollection  // Return a collection of tasks of the specified type
matching(condition: Closure): TaskCollection // Return a set of assigned task types

/ / create a task
create(name: String): Task
create(name: String, configure: Closure): Task 
create(name: String, type: Class): Task
create(options:Map<String, ? >): Task create(options:Map<String, ? >, configure: Closure): Task// Listen when a task is added to a TaskContainer
whenTaskAdded(action: Closure)
Copy the code
  // When a task is created
        project.getTasks().whenTaskAdded { Task task ->
            println "The task ${task.getName()} is added to the TaskContainer"
        }

        // Create (String var1)
        project.getTasks().create("task1")

        // Create (Map
      
        var1) to create
      ,?>
        project.getTasks().create([name: "task2".group: "MyGroup".description: "This is the description of task2.".dependsOn: ["task1"]])

        Closure VAR2 (String var1, Closure VAR2
        project.getTasks().create("task3", {
            group "MyGroup"
            setDependsOn(["task1"."task2"])
            setDescription "This is task3 description."
        })
Copy the code

perform

> Configure project :App Gradle. BeforeProject Calls app before -- Configure The task task1 is added to The TaskContainer The task task2 is added  to the TaskContainer The task task3 is added to the TaskContainerCopy the code

Incremental build of tasks

Gradle supports an up-to-date checking function. Gradle saves the results of each run and checks if the results have changed in the next run. If not, it skips the run to improve the speed of Gradle building

Usually a Task will have an intput and an output, and the input of the Task will affect the output

The figure shows a Java-compiled task, which has two inputs, one is the JDK version number, the other is the source file, and the output is a class file. Only when the version number and the source file change, the final compiled class file is different. After we execute the task once, if the input does not change, The result can be retrieved directly from the cache so that Gradle identifies the up-to-date and skips the Task execution

How do YOU implement incremental builds

An incremental build must specify one input and one output. As you can see from the preceding class diagram, task.getinputs () has type TaskInputs, task.getOutputs () has type TaskOuputs, and task.getOutputs () has type TaskOuputs. Outputs support inputs and outputs

task test1 {
    / / set the inputs
    inputs.property("name"."hjy")
    inputs.property("age".10)
    / / set the outputs
    outputs.file("$buildDir/test.txt")

    doLast {
        println "exec task task1"
    }
}

task test2 {
    doLast {
        println "exec task task2"}}Copy the code

First execution

> Task :app:Test1 exec task task1 Execution phase, task':app:test1'Time:0ms

> Task :app:Test2 exec task task2 The execution phase, task':app:test2'Time:0ms

Copy the code

The second execution, where test1 is no longer required to be repeated, is marked up to date, a typical incremental build

> Task :app:Test2 exec task task2 The execution phase, task':app:test2'Time:0ms

BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date

Copy the code

TaskInputs, taskOutputs

You can also listen to annotations to implement incremental builds when customizing tasks

Annotation name Attribute types describe
@Input Any Serializable type A simple input value
@InputFile File An input file, not a directory
@InputDirectory File An input directory, not a file
@InputFiles 可迭代 File list, containing files and directories
@OutputFile File An output file, not a directory
@OutputDirectory File An output directory, not a file
@OutputFiles Map < String, the File > or Iterable Output file list
@OutputDirectories Map < String, the File > or Iterable Output directory list
class SayHelloTask extends DefaultTask {
    
    // Define the input
    @Input
    String username;
    @Input
    int age

    // Define the output
    @OutputDirectory
    File destDir;

    @TaskAction
    void sayHello() {
        println "Hello $username ! age is $age"
    }

}

task test(type: SayHelloTask) {
    age = 18
    username = "hjy"
    destDir = file("$buildDir/test")}Copy the code

The $buildDir/test directory is generated after the Task is executed. When you execute the Task again, the incremental build will be performed. If you change the property value or delete the file, it will be executed again

reference

Android Gradle learning (3) : Task advanced learning

In-depth understanding of Gradle for Android

Gradle core decrypt (Gradle core decrypt)