The default tool for Android Studio is Gradle. Developers usually do not need to know Gradle script configuration to develop an App, but if you need to modify the output directory in the package to speed up the package, you need to have a deep understanding of Gradle. Gradle can not only be used as a tool to learn Gradle, but also as a programming framework. Here is the Gradle API document, and then we write and compile scripts. In fact, we are playing Gradle API.

Gradle consists of three parts:

  1. Groovy core syntax
  2. Build script block
  3. Gradle API: Contains project, Task/Settiing, and more, which will be highlighted next.

Gradle advantage

  1. In terms of flexibility, Gradle supports scripting based on the Groovy language and focuses on the flexibility of the build process. It is suitable for building projects with high complexity and can accomplish very complex builds.
  2. In terms of granularity, Gradle builds granular to each task. And all of its Task source is open source, after we master the whole packaging process, we can modify its Task to dynamically change its execution process.
  3. Gradle supports a plug-in mechanism for extensibility, so we can reuse plug-ins as easily as we reuse libraries.

Grale builds the life cycle

Running./gradlew build is one of the most complex task commands. (./gradlew is the syntax in MAC)

As you can see, each time the task takes a long time, because the build task depends on many tasks, and it will execute its own task after completing the task it depends on. Let’s take a look at the Gradle build process first.

The Gradle build process can be divided into three parts: the initialization phase, the configuration phase, and the execution phase.

Initialization phase

Gradle creates a Project instance for each Project. In a multi-project build, Gradle finds out which Project dependencies need to participate in the build. The script associated with initialization is settings.gradle, which reads out how many projects there are in the entire project.

The configuration phase

The tasks of the configuration phase are to execute the build.gradle script under each section, complete the Project configuration, and construct the Task dependency diagram to execute tasks according to the dependencies during the execution phase.

Gradle has a Project object for each build.gradle, and the code executed in the configuration phase includes statements in build.gralde, closures, and configuration section statements in Task.

Execution phase

At the end of the configuration phase, Gradle creates a directed acyclic graph based on the dependencies of the tasks. This can also be accessed through the getTaskGraph method of Gradle objects. The corresponding class is TaskExecutionGraph, which is then executed by calling Gradle < Task >.

Gradle lifecycle listens

Add lifecycle listeners to Project

Now let’s look at some of the most common listening methods in development:

// called before Project is configured
void beforeEvaluate(Closure closure)
// called after the Project configuration is complete
void afterEvaluate(Closure closure)
Copy the code

Here’s an example to verify the result:

setting.gradle

include ':app'

println 'Initialization phase begins... '
Copy the code

Build. gradle in the root directory

// Configure the submodule
subprojects { sub ->
    sub.beforeEvaluate { proj ->
        println "Subitem beforeEvaluate callback..."
    }
}

println "Root project configuration begins --"

task rootTest {
    println "Task Configuration in root project --"
    doLast {
        println "Execute root project task..."
    }
}

println "End of root project configuration --"
Copy the code

Build. gradle in app directory

println "APP subproject configuration starts --"

afterEvaluate {
    println APP subproject afterEvaluate callback...
}

task appTest {
    println "Task configuration in APP subproject --"
    doLast {
        println "Perform sub-project tasks..."
    }
}

println "End of APP subproject configuration --"
Copy the code

Run ‘./gradlew clean ‘to get the following output:

Initialization phase begins... Root project configuration start -- Task configuration in root project -- Root project configuration end -- subproject beforeEvaluate callback... APP subproject configuration start -- APP subproject task configuration -- APP subproject configuration end -- APP subproject afterEvaluate callback...Copy the code

Add a lifecycle listener to Gradle

In setting.gradle add:

include ':app'
gradle.addBuildListener(new BuildListener() {
  
  // called before the build starts
    void buildStarted(Gradle var1) {
        println 'Construction begins... '
    }
  
  // Settings. gradle is called after settings.gradle is configured
    void settingsEvaluated(Settings var1) {
        // var1.gradle.rootProject
        // Because the initialization of Project has not been completed.
        println 'Settings: Perform settingsEvaluated... '
    }
  
  // Called when all projects introduced in settings.gradle have been created. Settings only take effect in that file
    void projectsLoaded(Gradle var1) {
        println 'Settings: Execute projectsLoaded... '
        println 'Initialization completed, root project accessible:' + var1.gradle.rootProject
    }
  
  // called after all project configurations are complete
    void projectsEvaluated(Gradle var1) {
        println 'Settings: executive projectsEvaluated... '
    }
  
  // Child Project must be set in root project to take effect. Root project must be set in settings.gradle to take effect
  	void beforeProject { proj ->
    	println "Settings: Execute ${proj.name} beforeProject"
		}

  // called after project is configured
		void afterProject { proj ->
    	println "Settings: Execute ${proj.name} afterProject"
		}
  
  // called after the build is finished
    void buildFinished(BuildResult var1) {
        println 'Build complete'}})Copy the code

Take a look at the output:

Settings: Perform settingsEvaluated... Settings: Execute projectsLoaded... Settings: Run GradleTestDemo beforeProject Root project Configuration starts -- Task configuration in the root project -- Root project configuration ends -- Settings: Execute GradleTestDemo afterProject Settings: Execute app beforeProject subproject beforeEvaluate callback... APP subproject configuration start -- APP subproject task configuration -- APP subproject configuration end -- APP afterProject afterEvaluate callbacksettings:Perform projectsEvaluated... End of build...Copy the code

There are other listening methods:

this.gradle.beforeProject{}  // Equal to beforeEvaluate
this.graddle.afterProject{}  // Equivalent to afterEvaluate

// All of the following can be monitored
this.gradle.addListener
tthis.gradle.addProjectEvaluationListener
Copy the code

After learning about gradle’s life cycle listening, I wonder why other commands output when executing build commands. Here’s a picture:

This graph will be completed during the configuration phase, forming a directed acyclic graph. When executing a task named build, other dependent tasks will be completed.

TaskExecutionGraph

After being configured, Gradle generates directed acyclic graphs of all tasks. These are called task execution graphs. They determine the order in which tasks are executed, etc.

The TaskExecutionGraph API documentation shows the common API methods:

API describe
addTaskExecutionGraphListener Add a listener to the task execution diagram
addTaskExecutionListener Add a listener to the task execution
whenReady Called when the task execution diagram is filled
beforeTask When a task is called before it executes
afterTask This command is called when a task is completed
hasTask Query whether the task exists
getAllTasks Get all tasks
Set getDependencies(Task task) Returns the dependency of the parameter Task

Gradle also listens for the execution life cycle of a task.

TaskExecutionGraph taskGraph = gradle.getTaskGraph()
taskGraph.whenReady {
    println "task whenReady"
}

taskGraph.beforeTask { Task task ->
    println "Task name: ${task.name} beforeTask"
}

taskGraph.afterTask { Task task ->
    println ${task.name} afterTask
}
Copy the code

reference

In-depth understanding of Android Gradle

Explore Gradle automation building technology

After reading this series, you will understand Gradle completely

Gradle Foundation – Build lifecycle and Hook technology

Gradle build life cycle