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:
- Google super full kotlin learning Wang fried notes! Kotlin introduction to mastery + Advanced kotlin enhanced actual combat (with Demo)
- Alibaba's internal Jetpack dictionary unexpectedly flowed out! The ultimate classic can be called the ceiling of Android architecture components
- The boss is strong. Senior engineer stayed up late for half a month to sort out the "component practical combat learning manual", which is all the essence!
- Byte beating has uploaded an interview version of the interviewer Android interview, without any nonsense, it is all the essence.
- 606 latest Android interview questions with answers