Mastering Android Gradle

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

  • task
  • project

Master these two and you've mastered more than half of your Gradle knowledge.

Let's talk about Task first

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 environment variables beforehand, or you can use ./gradlewalternatives):

tasks

According to the above figure, you can see that each item in the current project has taskbeen listed, and there is a yellow output indicating the current taskdescription.
Among them, -qit means to ignore gradleits own loginformation. Adding this parameter can block many irrelevant outputs, and it will not affect the execution if it is not added.

Task declaration format

To declare a task, you only need to add taskit in front of the task name, for example, a helloTask is declared below.

task hello

Usually we attach some execution actions to the task, called Action, for example

hello.doFirst{
	println "hello first"
}

hello.doLast{
	println "hello last"
}

It can also be accompanied by a closure configuration, which is called Configuration, the closure can not only be used for assignment operations, but also can perform some automatic configuration.

hello {
	println "hello"
}

Task dependency

Declaring one alone taskwill hardly make any sense in actual development. More often, multiple taskgroups are combined, and one depends 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 hellotask, it will output hello, and when the worldtask is executed, because it is declared dependsOn: "hello", it means worlddependency hello, and hello will be executed first, and then the world will be executed.

task xxx << {
}

Such syntax is equivalent to

task xxx
xxx.dolast {
}

build.gradleYou can create a new text at any location called , to practice the taskdefinitions and dependencies described above.

tasks

Then talk about 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 and clever uses.

setting.gradle file

setting.gradleMany people don't know that you can also write code in Chinese . The following code is an example I mentioned in the previous article [ Enterprise Android Modular Platform Design Recommendationssetting.gradle ]. In the file, you can specify a projectlocation, where you can import a module 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 usage of each sub-resource, the dependency environment of the plugin, and so on.

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

Usually, when we refer to aars in each module, we will manually go through it in each module compile, such as supportpackages. But there is actually a very simple way to write it once, that is to declare this in the closure in the root gradlefile of the project .subprojectsdependencies

Usually when writing compiledependencies, we will write like this:

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

In fact gradle, this is a method call, and its essence is that the compile()method passes in a mapparameter, so the complete writing is actually like this:

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

At the same time, the usable keys of the map are not only the commonly used keys group, name, version, but also the less commonly used keys configuration, classifierand so on.

Look again at Task

Groovy is based on Java, but it adds a lot of closures on this basis to help develop build scripts more conveniently. If you don't know Groovy, it doesn't matter, just write it in Java, in fact, it is most appropriate to write it in Kotlin. If you don't know Kotlin yet, I highly recommend you to check out my [ Kotlin Primer ] series of articles

Each Task can configure its input and output. If the output of a Task is consistent with the previous output, it will not be executed repeatedly. UP-TO-DATEAt this point, it will output the latest results on the command line .
For example the following Task:

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()
    }
}

It will output after repeated executionUP-TO-DATE

tasks

Behind the action

The fastest way to learn any technology is to look at the source code. gradleThe source code is located in the srcdirectory. For example, the path on my computer 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 to view the code and comments, this is the best learning material .

task hello

In Groovy, method parentheses can be omitted, and quotes can also be omitted if the type of the string can be inferred

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. As in Kotlin, parentheses can be omitted when a 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 it for this chapter, and the next one is about how to create a Gradle plugin to dynamically add code (including jar packages) to a specified class or a newly generated class at compile time.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324441670&siteId=291194637