Recently I plan to learn how to use Gradle in Android. As a result, the articles published by Baidu are all introductory articles. Then I found the gradle website tutorials and masturbated to them.
Summary of Gradle.
Gradle is a project automation build tool based on Apache Ant and Apache Maven concepts. Instead of traditional XML, it uses a Groovy-based domain-specific language to declare project Settings. Gradle is the management of the project. It helps us with dependencies, packaging, deployment, distribution, and differential management of various channels.
Gradle advantage:
- One of the latest, most powerful build tools, use it to push the bar higher
- Using programs instead of traditional XML configuration makes project construction more flexible
- Rich third-party plugins, let you use as you like
- What Maven and Ant can do, Gradle can do, but what Gradle can do, Maven and Ant cannot do.
Groovy is an agile jVM-based development language that combines many of the powerful features of Python, Ruby, and Smalltalk. Groovy can integrate perfectly with Java and use all of Java’s libraries. It supports new language features such as dynamic typing and closures syntactically, seamlessly integrates all existing Java class libraries, and supports both object-oriented and procedural programming
The advantage of Groovy:
- A more agile programming language
- Getting started is very easy and very powerful
- It can be used as either a programming language or a scripting language
When I first started, I was confused about Gradle and Groovy. I thought they were the same language. Gradle is a build tool that uses Groovy.
Preparations:
Let’s go into action.
To use Gradle, you can create a new Android project in Android Studio. Use other IDE or need to configure the environment friends, you can baidu related articles.
The article examples are built on Gradle 5.1.1.
Task
Everything in Gradle is based on two basic concepts: projects and tasks.
Each Gradle build consists of one or more projects. What a project represents depends on what you are doing in Gradle. For example, a project might represent a JAR library or a Web application. It might represent a distribution ZIP assembled from jars produced by other projects. Projects don’t necessarily represent things to build. It might indicate something to accomplish, such as deploying the application to staging or production. Don’t worry just yet that doesn’t seem clear. Gradle’s conventionally built support adds a more concrete definition to the project definition.
Each project consists of one or more tasks. Tasks represent some atomic work performed by the build. This might be compiling some classes, creating jars, generating Javadoc, or publishing some archives to the repository.
Now, you’ll look at building some simple tasks in a project. Later sections cover working with multiple projects and more information about working with projects and tasks.
Hello world
Again, let’s start with Hello World. You can run a Gradle build using the following gradle commands. The gradle command looks for a file named build.gradle in the current directory. This build.gradle file is called a build script, although technically it is a build configuration script, as we’ll see later. The build script defines the project and its tasks.
To try this, create a build script named build.gradle below.
Example 1. For the first build script, go to build.gradle in your Android project and add the following code:
// build.gradle task hello { doLast { println 'Hello world! '}}Copy the code
In the project move to the included directory and execute the build script using the following command:
./gradlew -q hello // Android users use./gradlew in the root directoryCopy the code
Gradle -q hello // Use gradle for non-Android usersCopy the code
Run using the -q command-line option. This cancels Gradle’s log messages so that only the output of the task is displayed. This makes the sample output clearer. If you don’t want to, you don’t need to use this option.
The command to execute the build script is placed directly before the comment instead of being shown on a single line.
Define the task
Here you will see how to define tasks using strings as task names. There are some variations of this style that you may need to use in certain situations.
task('hello') {
doLast {
println "hello"
}
}
task('copy', type: Copy) {
from(file('srcDir'))
into(buildDir)
}
Copy the code
The two tasks created above are Hello and copy. There is an alternative syntax for defining tasks that you might prefer to use:
tasks.create('hello') {
doLast {
println "hello"
}
}
tasks.create('copy', Copy) {
from(file('srcDir'))
into(buildDir)
}
Copy the code
There are also two tasks created above: Hello and copy. Finally, Groovy and Kotlin DSLS have language-specific syntax:
// Using Groovy dynamic keywords
task(hello) {
doLast {
println "hello"
}
}
task(copy, type: Copy) {
from(file('srcDir'))
into(buildDir)
}
Copy the code
Build scripts using code
Gradle build scripts give you all the power of Groovy and Kotlin. As an appetizer, look at this: Using Groovy or Kotlin in Gradle tasks:
// gradle -q upper
task upper {
doLast {
String someString = 'mY_nAmE'
println "Original: $someString"
println "Upper case: ${someString.toUpperCase()}"
}
}
Copy the code
// gradle -q count
task count {
doLast {
4.times { print "$it "}}}Copy the code
Copy the code
Dependencies between tasks
DependsOn: Tasks can have dependencies between tasks.
// gradle -q intro task hello { doLast { println 'Hello world! ' } } task intro { dependsOn hello doLast { println "I'm Gradle" } }Copy the code
Dependent tasks can be declared later, but an error will be reported if they are not declared:
// gradle -q taskX
task taskX {
dependsOn 'taskY'
doLast {
println 'taskX'
}
}
task taskY {
doLast {
println 'taskY'
}
}
Copy the code
Task taskX depends on taskY, which is postdeclared.
You can define task dependencies in a number of ways. In Task Dependencies, you learned about defining dependencies using task names. Task names can refer to tasks in the same project as the task, or to tasks in other projects. To reference a task in another project, add the path of the project to which it belongs before the task name. Here is an example of adding dependencies from projectA:taskX to projectB:taskY:
// gradle -q taskX
project('projectA') {
task taskX {
dependsOn ':projectB:taskY'
doLast {
println 'taskX'
}
}
}
project('projectB') {
task taskY {
doLast {
println 'taskY'
}
}
}
Copy the code
In this case, projectA, projectB should be changed to the name of your project. Simply put, tasks at different levels can depend on each other.
Dynamic task
Groovy or Kotlin’s capabilities can be used to define functionality beyond tasks. For example, you can also use it to create tasks on the fly.
// gradle -q task1
4.times { counter ->
task "task$counter" {
doLast {
println "I'm task number $counter"
}
}
}
Copy the code
Task0, Task1, task2, task3
Operations on created tasks
Once a task is created, it can be accessed through API **. For example, you can dynamically add dependencies to tasks at run time.
// gradle -q task0
4.times { counter ->
task "task$counter" {
doLast {
println "I'm task number $counter"
}
}
}
task0.dependsOn task2, task3
Copy the code
Alternatively, you can add behavior to an existing task.
// gradle -q hello
task hello {
doLast {
println 'Hello Earth'
}
}
hello.doFirst {
println 'Hello Venus'
}
hello.configure {
doLast {
println 'Hello Mars'
}
}
hello.configure {
doLast {
println 'Hello Jupiter'
}
}
Copy the code
Calls to doFirst and doLast can be performed multiple times. They add actions to the beginning or end of the task action list. When a task is executed, the actions in the action list are performed in sequence.
Groovy DSL shortcut notation
There is a convenient notation for accessing existing tasks. Each task can be used as an attribute of the build script:
// gradle -q hello task hello { doLast { println 'Hello world! ' } } hello.doLast { println "Greetings from the $hello.name task." }Copy the code
In this example, by getting the name of the task, you know that this is what the task from Task Hello does. This improves the readability of your code, especially when using tasks provided by plug-ins, such as the Compile task.
Additional task attributes
You can add your own properties to the task. Add a property named myProperty and set an initial value for ext.myProperty. Properties can be read and set just like predefined task properties.
// gradle -q printTaskProperties
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties {
doLast {
println myTask.myProperty
}
}
Copy the code
The default task
Gradle allows you to define one or more default tasks if no other tasks are specified.
// gradle -q defaultTasks 'clean', 'run' task clean { doLast { println 'Default Cleaning! ' } } task run { doLast { println 'Default Running! ' } } task other { doLast { println "I'm not a default task!" }}Copy the code
This is equivalent to running Gradle Clean Run. In a multi-project build, each subproject can have its own specific default task. If the child project does not specify a default task, the parent project’s default task (if defined) is used
Configure through DAG
As we will describe in more detail later (see Build Lifecycle), Gradle has a configuration phase and an execution phase. After the configuration phase, Gradle knows all the tasks that should be executed. Gradle gives you an opportunity to take advantage of this information. One use case is to check whether the publish task is in the task to be executed. From there, you can assign different values to certain variables.
In the following example, the execution of the Distribution and release tasks results in different values for the version variable.
// gradle -q distribution // gradle -q release task distribution { doLast { println "We build the zip with version=$version" } } task release { dependsOn 'distribution' doLast { println 'We release now' } } Gradle. TaskGraph. WhenReady {taskGraph - > if (taskGraph. HasTask (" : the release ")) {version = '1.0'} else {version = '1.0 the SNAPSHOT'}}Copy the code
You can see that executing different tasks has different results here.
Build the external dependencies of the script
If the build script needs to use external libraries, you can add them to the classpath of the script in the build script itself. You do this using the buildscript() method and pass in a block that declares the buildscript classpath.
buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'}}Copy the code
The blocks of code in the buildScript () method form ScriptHandler instances. You can declare the build script classpath by adding dependencies to the CLASspath configuration. This is the same way you declare the Java compilation classpath. You can use any dependency type other than project dependencies.
Once the build script classpath is declared, the classes in the build script can be used just like any other class on the class path. The following example adds to the previous example and uses classes from the build script classpath.
// gradle -q encode import org.apache.commons.codec.binary.Base64 buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'}} task encode {doLast {def byte[] encodedString = new Base64().encode('hello world\n'.getBytes()) println new String(encodedString) } }Copy the code
The dependency is added, and then a task is created that references the classes in the dependency to encrypt the string.
Access the properties of the task
You usually need to find the tasks defined in the build file, for example, to configure them or use them for dependencies. There are many ways to do this. First, just like defining tasks, Groovy and Kotlin DSLS have language-specific syntax
task hello
task copy(type: Copy)
// Access tasks using Groovy dynamic properties on Project
println hello.name
println project.hello.name
println copy.destinationDir
println project.copy.destinationDir
Copy the code
Tasks can also be obtained through the Tasks collection.
task hello
task copy(type: Copy)
println tasks.hello.name
println tasks.named('hello').get().name
println tasks.copy.destinationDir
println tasks.named('copy').get().destinationDir
Copy the code
You can access the task from any project using the path of the task using the tasks.getbypath () method. You can call this method with getByPath() using the task name, relative path, or absolute path.
project(':projectA') {
task hello
}
task hello
println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path
println tasks.getByPath('projectA:hello').path
println tasks.getByPath(':projectA:hello').path
Copy the code
Pass the parameters to the task constructor
Instead of configuring the variable properties of a variable after the Task is created, you can pass parameter values to the constructor of the Task class. To pass the value to the Task constructor, you must use the annotated constructor @javax.inject.Inject.
class CustomTask extends DefaultTask {
final String message
final int number
@Inject
CustomTask(String message, int number) {
this.message = message
this.number = number
}
}
Copy the code
You can then create a task and pass the constructor arguments at the end of the argument list.
tasks.create('myTask', CustomTask, 'hello', 42)
task myTask(type: CustomTask, constructorArgs: ['hello', 42])
Copy the code
Either way is fine. In all cases, the value passed as a constructor parameter must be non-NULL. If you try to pass a null value, Gradle will throw a NullPointerException indicating which runtime value is NULL.
Add a description to the task
You can add a description to the task. This description is displayed when gradle Tasks is executed.
// gradle tasks
task copy(type: Copy) {
description 'Copies the resource directory to the target directory.'
from 'resources'
into 'target'
include('**/*.txt', '**/*.xml', '**/*.properties')
}
Copy the code
Change the task
Sometimes you want to replace tasks. For example, if you want to swap tasks added by a Java plug-in with other types of custom tasks. You can do this using the following methods:
// gradle -q copy
task copy(type: Copy)
task copy(overwrite: true) {
doLast {
println('I am the new one.')
}
}
Copy the code
When defining a new task, the overwrite property must be set to true. Otherwise, Gradle raises an exception saying that a task with that name already exists.
Skip the task
Gradle provides several ways to skip the execution of a task.
Using a predicate
You can use the onlyIf() method to attach the predicate to the task. The action of the task is performed only if the predicate is evaluated to true. You implement the predicate as a closure. The closure is passed to the task as an argument and returns true if the task should be executed; Return false if the task should be skipped. Evaluate predicates before the task is to be executed.
// gradle hello -PskipHello task hello { doLast { println 'hello world' } } hello.onlyIf { ! project.hasProperty('skipHello') }Copy the code
Using StopExecutionException
If the logic of skipping a task cannot be represented by a predicate, StopExecutionException can be used. If an action raises this exception, further execution of the action and any subsequent actions of the task are skipped. The build moves on to the next task.
// gradle -q myTask task compile { doLast { println 'We are doing the compile.' } } compile.doFirst { // Here you would put arbitrary conditions in real life. // But this is used in an integration test so we want defined behavior. if (true) { throw new StopExecutionException() } } task myTask { dependsOn('compile') doLast { println 'I am not affected' } }Copy the code
Enable and disable tasks
Each task has a enabled flag which defaults to true. Setting it to false prevents any task action from being performed. Disabled tasks are marked skip.
task disableMe {
doLast {
println 'This should not be printed if the task is disabled.'
}
}
disableMe.enabled = false
Copy the code
Mission timeouts
Each task has a timeout property that can be used to limit its execution time. When a task reaches timeout, the task execution thread is interrupted. The task will be marked as failed. The finalizer task will still run. If –continue is used, other tasks can continue after this point. Tasks that do not respond to interrupts cannot time out. All of Gradle’s built-in tasks respond to timeout in a timely manner
task hangingTask() {
doLast {
Thread.sleep(100000)
}
timeout = Duration.ofMillis(500)
}
Copy the code
Task rules
Sometimes you want to perform a task whose behavior depends on a large or infinite number of parameter values. A good way to provide such tasks is with task rules:
// gradle -q pingServer1
tasks.addRule("Pattern: ping<ID>") { String taskName ->
if (taskName.startsWith("ping")) {
task(taskName) {
doLast {
println "Pinging: " + (taskName - 'ping')
}
}
}
}
Copy the code
Rules are not only used when calling tasks from the command line. You can also create dependsOn relationships on rules-based tasks:
// gradle -q groupPing
tasks.addRule("Pattern: ping<ID>") { String taskName ->
if (taskName.startsWith("ping")) {
task(taskName) {
doLast {
println "Pinging: " + (taskName - 'ping')
}
}
}
}
task groupPing {
dependsOn pingServer1, pingServer2
}
Copy the code
If you run “Gradle -q Tasks”, you will not find the tasks named “pingServer1” or “pingServer2”, but the script is executing the logic based on the request to run these tasks.
Finalizer tasks
Finalizer Tasks are automatically added to the task diagram when a Finalizer task is scheduled to run.
// gradle -q taskX task taskX { doLast { println 'taskX' } } task taskY { doLast { println 'taskY' } } taskX.finalizedBy taskYCopy the code
Finalizer Tasks are executed even if the termination task fails.
// gradle -q taskX
task taskX {
doLast {
println 'taskX'
throw new RuntimeException()
}
}
task taskY {
doLast {
println 'taskY'
}
}
taskX.finalizedBy taskY
Copy the code
Running results:
Output of gradle -q taskX
> gradle -q taskX
taskX
taskY
FAILURE: Build failed with an exception.
* Where:
Build file '/home/user/gradle/samples/groovy/build.gradle' line: 4
* What went wrong:
Execution failed for task ':taskX'.
> java.lang.RuntimeException (no error message)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 0s
Copy the code
Finalizer tasks are useful in situations where you build resources that must be cleaned up whether the build fails or succeeds. An example of such a resource is a Web container that starts before integration test tasks and should always be closed even if some tests fail.
To specify a finalizer Task, use task.finalizedby (java.lang.object…). Methods. This method accepts the Task instance, Task name or task.dependson (java.lang.object…) Any other input accepted.
That’s the end of the task explanation.