20 minutes to master Android Gradle

At present, the domestic exploration in the field of Android has become deeper and deeper. Many technical fields, such as plug-in, hot repair and system construction, have urgent needs for Gradle. If you don't understand Gradle, you will not be able to complete the above things. So Gradle has to learn.

Almost everything in Gradle is based on these two basic concepts:

  • task
  • project

If you master these two, you will master more than half of Gradle's knowledge.

Let's start with Task

It is literally understood as a Task. All events executed in Gradle are executed by Task. For example, we create a new Android project and enter in its root directory:

gradle tasks -q

You can see the following output (you may need to configure gradle's environment variable in advance, or you can use. / gradlew instead):

According to the above figure, we can see that each task in the current project has been listed, and the Yellow output represents the description of the current task. Where - q means ignoring the log information of gradle itself. Adding this parameter can shield many irrelevant outputs, and it will not affect the execution.

Task declaration format

To declare a task, you only need to add task before the task name. For example, the following declares a hello task.

task hello

Usually, we attach some execution actions to the task, which are called actions, such as

hello.doFirst{
    println "hello first"
}

hello.doLast{
    println "hello last"
}

You can also attach a closure Configuration, called Configuration, which can not only be used for assignment, but also perform some automatic configurations.

hello {
    println "hello"
}

Task dependency

It is almost meaningless to declare a task alone in actual development. More often, it is to combine multiple tasks, one relying on the other, to form a series of task sets.

task hello

hello.doFirst{
    println "hello "
}

task world(dependsOn: "hello") << {
    println "world"
}

The above code defines two tasks. When we execute the Hello task, we will output "hello". When we execute the world task, because we declare dependsOn: "hello", which means that the world depends on Hello, we will execute hello first and then the world.

task xxx << {
}

This syntax is equivalent to

task xxx
xxx.dolast {
}

You can create a new one called build. Com anywhere Gradle text to practice the task definition and dependency described above.

Go on to Project

Android
   │ 
   ├──app
   │   └──build.gradle
   │
   ├──library
   │   └──build.gradle
   │
   ├──*.properties
   │
   ├──build.gradle
   │
   └──setting.gradle

An Android project is usually composed of the above structure, which has many unknown clever uses.

setting.gradle file

About setting Gradle can also write code, which many people don't know. The following code is my last article[ Design suggestions for enterprise Android modular platform ]An example mentioned in setting In the gradle file, you can specify a project location, where you can import modules from an external project into the APP project.

getLocalProperties().entrySet().each { entry ->
    def moduleName = entry.key
    if (Boolean.valueOf(entry.value)) {
        def file = new File(rootProject.projectDir.parent, "/${moduleName.replace("\\W", "")}/${moduleName.toLowerCase()}")
        if (file.exists()) {
            include ":${moduleName.toLowerCase()}"
            project(":${moduleName.toLowerCase()}").projectDir = file
        }
    }
}

build.gradle

The root gradle file of a project is used to describe the unified resources of the project, including the use of sub resources, the dependency environment of plug-ins, and so on.

subprojects{
    apply plugin: 'com.android.library'
    dependencies {
      compile 'com.xxx.xxx:xxx:1.0.0'
   }
}

Generally, when we refer to aar in each module, we will manually compile it in each module, such as support package. But in fact, there is a very simple way. Just write it once, that is, declare the dependencies in the subprojects closure in the root gradle file of the project.

Usually, when writing compile dependencies, we will write as follows:

compile 'com.android.support:appcompat-v7:25.0.0'

In fact, in gradle, this is a method call. Its essence is that the compile() method passes in a map parameter. Therefore, the complete writing method is actually as follows:

compile group: 'com.android.support' name:'appcompat-v7' version:'25.0.0'

At the same time, the available key s of map include not only the commonly used group, name and version, but also the rarely used configuration, classifier and so on.

Look at the Task again

Groovy is based on Java, but it adds a lot of closures to help develop and build scripts more conveniently. If you don't know groovy, it doesn't matter. Just write it as Java. In fact, it's most appropriate to write it as Kotlin. If you don't know Kotlin yet, I strongly recommend you check my [ Kotlin Primer ] series of articles

Each Task can be configured with its input and output. If the output of a Task is consistent with the previous output, it will not be executed repeatedly. At this moment, UP-TO-DATE will be output in the command line, indicating that it is the latest result. For example, the following tasks:

task transform {
    ext.srcFile = file('hello.txt')
    ext.destDir = new File(buildDir, 'generated')
    inputs.file srcFile
    outputs.dir destDir
    doLast {
        destDir.mkdirs()
        def ins = new BufferedReader(new FileReader(srcFile))
        def stringBuilder = new StringBuilder()
        def temp
        while ((temp = ins.readLine()) != null) {
            stringBuilder.append(temp)
        }
        def destFile = new File(destDir, "world.txt")
        destFile.text = stringBuilder.toString()
    }
}

UP-TO-DATE will be output after repeated execution

Behind the operation

The quickest way to learn any technology is to look at the source code. The source code of gradle is located in the SRC directory. For example, my local path is: / users / Zhangtao / Gradle / wrapper / dists / gradle-3.3-all / 55gk2rcmfc6p2dg9u9ohc3hw9 / gradle-3.3/src create a new ordinary Java project locally. Import the source code and view the code and comments. This is the best learning material.

task hello

In Groovy, method parentheses can be omitted. If the type of string can be inferred, quotation marks can also be omitted

public interface org.gradle.api.Project{
    Task task(String name);
    Task task(String name, Closure configureClosure);
}

// TaskFactory
public TaskInternal createTask(Map<String, ?> args) {
}

Closures exist to better initialize objects. Like Kotlin, parentheses can be omitted when the closure is used as the last parameter.

Copy a = task(myCopy, type: Copy)
a.from 'resources'
a.into 'target'
a.include('**/*.txt', '**/*.xml', '**/*.properties')

Equivalent to

task myCopy(type: Copy)

myCopy {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

That's all for this chapter. The next chapter will talk about how to create a Gradle plug-in and dynamically add code (including in the jar package) to the specified class or newly generated class when compiling.

Review of previous periods:

Tags: Java Interview kotlin entry Groovy def strip

Posted by Aretai on Sat, 16 Apr 2022 18:37:45 +0930