banner
jzman

jzman

Coding、思考、自觉。
github

Gradle Series: Basics of Build Scripts

This article introduces and explores Gradle as a whole, covering concepts such as Task, Project, and other common operations for building projects using Gradle. The main contents are as follows:

  1. Setting file
  2. Build file
  3. Project and Tasks
  4. Task creation
  5. Task dependencies
  6. Interaction between tasks
  7. Custom properties
  8. Summary

Setting file#

Let's talk about the Setting file for building projects with Gradle. This file is mainly used to configure the current project. For example, in an Android development project, there may be multiple sub-modules. When a certain sub-module is not needed, its configuration can be removed from the Setting file. Only the sub-modules configured in the Setting file will be built. This applies not only to Android development but also to any project built with Gradle. Setting is the default name for the Gradle project configuration file. Let's test the usage of the Setting.gradle file with the following project directory:

├─GradleSetting
│  ├─.gradle
│  │  ├─4.1
│  │  │  ├─fileChanges
│  │  │  ├─fileHashes
│  │  │  └─taskHistory
│  │  └─buildOutputCleanup
│  └─test
│      └─Method
│          └─.gradle
│              ├─4.1
│              │  ├─fileChanges
│              │  ├─fileHashes
│              │  └─taskHistory
│              └─buildOutputCleanup
│ build.gradle
│ setting.gradle

In the project named GradleSetting, there is a sub-project named Method under the test folder. We will use the setting.gradle file to include the Method sub-project in GradleSetting. The content of the setting.gradle file is as follows:

println "---------test----Setting.gradle----------"
// Output the current project directory
println(rootDir)
// Specify the sub-project to be built
include ':Method'
project(':Method').projectDir = new File(rootDir,'test/Method')

Let's take a look at the output:

PS E:\Gradle\study\GradleSetting> gradle testGradleSetting
---------test----Setting.gradle----------
E:\Gradle\study\GradleSetting

> Configure project :
testGradleSetting

> Configure project :Method
3
3
30
Result of the method: 30
1
2
3
4
5


BUILD SUCCESSFUL in 2s

Because Method is configured in the setting.gradle file, it is indeed included in the build. If it is not configured in the setting.gradle file, it will not be built. It is recommended to verify it yourself.

The location of the Method sub-project is configured in the setting.gradle file. If not specified, it defaults to the same level as the setting.gradle file.

Build file#

If you choose to build a project with Gradle, each project will have a build.gradle file, which is the entry point for project building and applies to the entire project. You can configure common settings for sub-projects in the root project, such as configuring the repository for sub-projects as jcenter, so that all dependencies in the sub-projects will be downloaded from the jcenter repository. Here is an example:

// Configure the repository for sub-projects
subprojects{
    repositories{
        jcenter()
    }
}

// Configure all projects
allprojects{
    
}

...

The main purpose of this section is to understand the role of the build.gradle file. In actual development, there will be more detailed configuration strategies for different types of projects.

Project and Tasks#

In Gradle, there are many Projects. A Project can be packaged into a jar and used by another Project. Each Project is a sub-module abstracted based on its business requirements, and is ultimately built into a complete project using Gradle.

Each Project can have multiple tasks. A Task is a unit of work that accomplishes a specific functionality, such as the wrapper task that creates the wrapper files.

Task creation#

We are already familiar with task creation. Let's use the task keyword to declare a task:

// Create a task
task createTask{
    doFirst{
        println 'doFirst'
    }

    doLast{
        println 'doLast'
    }
}

// Create a task using TaskContainer, which is already defined in Project as tasks
tasks.create("createTask1"){
    doFirst{
        println 'doFirst'
    }

    doLast{
        println 'doLast'
    }
}

task can be understood as the keyword for creating a task. In fact, task is a method in Project. In Groovy, parentheses on method parameters can be omitted, and the content in curly braces is a closure that configures the task. doFirst and doLast are two commonly used methods in Task, which will be executed at the beginning and end of the task, respectively.

Task dependencies#

Tasks can depend on each other, allowing control over the order of task execution. For example, task A must be executed before task B. In this case, task A depends on task B. Here is an example:

// Single task dependency: specify the task to depend on using dependsOn
task B(dependsOn: A){
    doFirst{
        println 'B'
    }
}

task C{
    doFirst{
        println 'C'
    }
}

// Multiple task dependencies
task D{
    dependsOn A, C
    doFirst{
        println 'D'
    }
}

Let's see the execution result of the task with multiple dependencies, gradle D:

PS E:\Gradle\study\GradleSetting> gradle D

> Task :A
A

> Task :C
C

> Task :D
D

BUILD SUCCESSFUL in 2s

Clearly, when executing task D, the other two tasks it depends on are executed first, controlling the order of task execution.

Note: Scripts are executed in order. If tasks A and C are defined after task D, an error will occur when executing task D.

Interaction between tasks#

Each created task has its own name and is of type Task. Therefore, we can control the execution of tasks using the Task API. The principle of operating tasks using their names is that when a task is created, Gradle has already declared it as a property of the Project object with the type Task. Here is an example:

// Interaction between tasks
task E{
    println 'hello e'
    println "Is E a property of Project: "+project.hasProperty('E')
}

E.doFirst{
    println 'doFirst'
}

E.doLast{
    println 'doLast'
}

The execution result of the above code is:

PS E:\Gradle\study\GradleSetting> gradle E

> Configure project :
hello e
Is E a property of Project: true

> Task :E
doFirst
doLast


BUILD SUCCESSFUL in 1s

Custom properties#

Both Project and Task allow users to add additional custom properties using the corresponding ext property. After adding, these custom properties can be read and set using the ext property. If you want to add multiple custom properties at the same time, you can use the ext block. Here is an example of defining custom properties:

apply plugin:"java"

// Define a single custom property
ext.name1 = "Gradle"
// Define multiple custom properties
ext{
    age = 10
    score = 100
}

// Use custom properties in SourceSet
sourceSets.all{
    ext.resourceDir = null
}

// Configure custom properties
sourceSets{
    main{
        resourceDir = "main/res"
    }
    test{
        resourceDir = "test/res"
    }
}

task customProperty{
    println "name=${name1}"
    println "age=${age}"
    println "score=${score}"

    sourceSets.each {
        println "${it.name} resourceDir is ${it.resourceDir}"
    }
}

The execution result of the above code is:

PS E:\Gradle\study\GradleSetting> gradle customProperty

> Configure project :

name=Gradle
age=10
score=100
main resourceDir is main/res
test resourceDir is test/res

BUILD SUCCESSFUL in 2s

Custom properties have a wider scope than local variables and can be accessed across tasks and projects as long as the objects that own these properties can be accessed. In Android development, custom properties can be used to define version numbers, version names, and versions of third-party libraries used in a separate gradle file, which can be accessed by each module, making it easier to manage library versions and improving work efficiency to some extent.

Summary#

Gradle scripts are based on Groovy, which is fully compatible with Java syntax. Gradle scripts are essentially code, and Gradle provides syntax to accomplish related tasks. The Gradle series of articles are as follows:

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.