Android Gradle Task usage details

As a build tool, in addition to the tasks brought by plugins, we can also customize many variables, tasks, or inherit certain tasks to re-specify input and output files. First of all, we need to clarify the Gradle cycle. In short, there are three steps when a Gradle task is executed.

  1. Gradle will analyze the build script and generate instances of settings and project classes corresponding to the projects configured by setting.gradle.
  2. Initialize the configuration, configure the properties of the project object by executing the build.gradle script of each project, and also create and configure tasks and related information at this stage.
  3. Execute specific tasks, and perform a series of task executions through the dependencies between tasks.

After clarifying these, let's take a look at the related use of tasks. Here we create a new Android project, including an app and a library.
settings.gradle

include ':app', ':mylibrary'

Then our project has three project instances, rootProject, app, mylibrary

configuration variable

1. Define variables directly in the gradle file

We define it directly at the end of the app's build.gradle.

def para='123'
println para

Then we execute and
write picture description here
we can see the corresponding output

15:22:36: Executing task 'assembleDebug'...

Executing tasks: [assembleDebug]

Configuration on demand is an incubating feature.
G:\program\Android\sdk\platform-tools\adb.exe
123
:app:preBuild UP-TO-DATE
:mylibrary:preBuild UP-TO-DATE
:mylibrary:preDebugBuild UP-TO-DATE
:mylibrary:checkDebugManifest UP-TO-DATE
:mylibrary:processDebugManifest UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:mylibrary:compileDebugAidl UP-TO-DATE
.....

Obviously we can see that the output is before the task execution. This means that the code has already been executed during the configuration phase. Variables defined like this are only visible within that file

2. Use ext to define variables

It is also defined in the app's build.gradle as follows, and the assembleDebug task is also executed through the gradle window. If it remains unchanged, I will not go into details.

ext{
    para1 ="456"
}
assert project.ext.para1=='456'
assert ext.para1=='456'

Variables defined in this way can be obtained in other modules, but they must be defined. For example, if they are defined in the app, they can be obtained in mylibrary, because the build.gralde of the app is executed first.
We can get the value in build.gradle in mylibrarya.

assert rootProject.childProjects.'app'.ext.para1=='456'

Similarly, we define ext in the build.gradle of the root directory, which is obtained through rootProject.ext.

(1) Add the config.gradle file

ext can be brought in by creating files individually. Add a config.gradle file in the root directory. The content is as follows:

ext{
        pubg='pubg'
}

Then we add in build.gradle in the root directory

apply from: "config.gradle"

Writing in this way is similar to the principle of #include in C language, and is directly similar to pasting code. Then we can get variables in other modules.

assert rootProject.ext.pubg=='pubg'

3. Read the properties file

We create a new app.properties file in the app directory and enter the following content.

key.file=C\:\\work\\Key.jks
keyAlias=key
keyPassword=key7766
storePassword=key6677

Then we can read the file in build.grald to get the corresponding properties.


Properties properties = new Properties()
InputStream inputStream = file('app.properties').newDataInputStream() ;
properties.load(inputStream)
println properties['key.file']
println properties['keyAlias']
println properties['keyPassword']
println properties['storePassword']

result:

C:\work\Key.jks
key
key7766
key6677

Pay attention to the path of the file here. If it is the root directory, call rootProject.file(), and if it is the corresponding module directory, call file() directly. This method is a relative path corresponding to the project directory

Configure custom tasks

1. Simple definition of Tasks

There are two definitions

task A<<{
    println 'A task'
}
task B{
    println 'B task'
}

The difference between the two definitions is: B will be executed in the configuration phase, while A needs to specifically execute the A task or as a dependency of other tasks. In fact, this way of defining A will be removed in Gradle 5.0, so it is not recommended to use it. We can specify this by specifying doLast{}.

task A{
    doLast {
        println 'doLast'
    }
    doFirst {
        println 'doFirst'
    }
    doLast {
        println 'doLast1'
    }
    doLast {
        println 'doLast2'
    }
}

result:

doFirst
doLast
doLast1
doLast2

Specify task grouping and description

task B{
    group "custom tasks"
    description '任务描述'
}

When we synchronize, we can find custom groupings and descriptions in the window.
write picture description here

Pass arguments for project using the command line

task searchParameters {
    doLast {
        println project.hasProperty("pp")?pp:'can not find field'
    }

}

Execute tasks with camelCase on the command line

gradle :app:sP -Ppp=nihao

result:

nihao
2. Use DefaultTask to add custom tasks
class IncrementTask extends DefaultTask {

    @TaskAction
    void run() {
        println 'IncrementTask'

    }
}
//方式一
tasks.create('increment', IncrementTask)
//方式二 理解为继承
task increment(type: IncrementTask) {

}

Similarly, we can specify grouping and description, which are added in the constructor of IncrementTask.

IncrementTask() {
        group '自定义任务分组'
        description '任务描述'
    }

Use upToDate to skip tasks, which we also add in the constructor.

    outputs.upToDateWhen { true }

In this way, it can be judged whether the task needs to be skipped for the second and subsequent executions according to the return value of the closure.

Specify the input and output files and attributes of the task

class IncrementTask extends DefaultTask {



    @TaskAction
    void run() {
        println 'IncrementTask'
        println inputs.files.first()
        println inputs.files.singleFile
        println outputs.files.first()
        println inputs.getProperties().'prop1'
    }
}


task increment(type: IncrementTask) {
    inputs.file file('text')
    inputs.property 'prop1','this is a register property'
    outputs.file file('outputs')
}

result:

IncrementTask
C:\Users\TY\Desktop\memoryoptimize\TestApplication\app\text
C:\Users\TY\Desktop\memoryoptimize\TestApplication\app\text
C:\Users\TY\Desktop\memoryoptimize\TestApplication\app\outputs
this is a register property
3. Inherit the original task

Here we use the Gradle plugin's Zip task to package the apk file into a zip package. Add it to the app's build.gradle.

//在分析完成gradle 之后执行
afterEvaluate {
    task zip(type: Zip,dependsOn:'assembleDebug') {
        archiveName 'my.zip'
        destinationDir file("${buildDir}/zip")
        println tasks.getByName('assembleDebug')
        from tasks.getByName('packageDebug').outputs.files[1]
    }
}

By performing this task, we packaged all files under app\build\outputs\apk\debug into app\build\zip\my.zip. Inheriting the original task basically only needs to specify the input and output.
We can find some original tasks in gradle-4.4\src\core\org\gradle\api\tasks.
write picture description here
There are copy, delete, etc. in it, you can view the source code if you need to use it.

4. Task Dependency

Tasks can depend on each other, such as letting A be executed after B, or A must be executed after B is executed, etc. There are mainly the following types.

relation discirbe
A dependsOn B Task B must be executed before task A is specified
A mustRunAfter B Specify that the B task is executed before the A task, but it is not a dependency. If only the A task is executed, it is not necessary to execute B
A shouldRunAfter B Under parallel compilation, A is not necessarily executed after B
A finalizedBy B After A is executed, B must be executed

simply do a test

task A  {
    doLast{
        println 'A'
    }
}


task B  {
    doLast{
        println 'B'
    }
}

task MyTask(dependsOn: [B, A])  {
    doLast{
        println 'mytask'
    }
}
task finalized  {
    doLast{
        println 'finalized'
    }
}
A.finalizedBy finalized

result:

:app:A
A
:app:finalized
finalized
:app:B
B
:app:MyTask
mytask

Before MyTask is executed, A is executed, then finalized is executed, then B, and finally MyTask. There is a problem here. The dependency specified by MyTask is obviously [B, A], but the execution order is A->B. Here, if you want B to execute before A, you need to specify A dependsOn B additionally.

Guess you like

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