Android Gradle Task使用详解

Gradle作为一个构建工具,除了插件给我们带来的task,我们也可以自定义很多变量,task,或者继承某些task来重新指定输入输出文件等。首先我们要明确一下Gradle的周期,简单来说,一个Gradle任务执行的时候会有三个步骤。

  1. Gradle会分析构建脚本,通过setting.gradle配置的项目对应生成settings与project类的实例。
  2. 初始化配置,通过执行各个项目build.gradle脚本,配置project对象的属性, 此阶段也会去创建、配置task及相关信息。
  3. 执行具体的任务,通过任务之间的依赖关系来进行一系列的任务执行。

明确了这些之后我们就了解一下task的相关使用吧。这里我们新建一个Android项目,包含一个app和一个library。
settings.gradle

include ':app', ':mylibrary'

那么我们这个项目就有了三个project实例,rootProject,app,mylibrary

配置变量

1.在gradle文件中直接定义变量

我们在app的build.gradle中末尾直接定义。

def para='123'
println para

然后我们执行
Android Gradle Task使用详解_第1张图片
就可以看到对应的输出

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
.....

很明显我们可以看到输出是在任务执行之前的。这就表示配置阶段就已经执行了代码。这样定义的变量只在该文件内可见

2.使用ext定义变量

同样在app的build.gradle中定义如下,同样通过gradle的窗口执行assembleDebug任务,后面如果不变就不赘述了。

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

这样定义的变量可以在其他module中获取,但是必须要定义之后才行,比如这里定义在app里的,可以在mylibrary中获取,因为app的build.gralde是先执行的。
我们可以在mylibrarya中的build.gradle中获取值。

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

同样我们在根目录的build.gradle中定义ext,就通过rootProject.ext来获取。

(1) 添加config.gradle文件

可以通过单独创建文件来引入ext。在根目录中添加config.gradle文件。内容如下:

ext{
        pubg='pubg'
}

然后我们在根目录的build.gradle中添加

apply from: "config.gradle"

这样写和c语言中#include原理类似,直接类似于粘贴代码。然后我们就可以在其他模块中获取变量了。

assert rootProject.ext.pubg=='pubg'

3.读取properties文件

我们在app的目录下新建app.properties文件,并输入以下内容。

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

然后我们在build.grald中就可以读取文件来获取对应的属性。


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']

结果:

C:\work\Key.jks
key
key7766
key6677

这里注意一下文件的路径,如果是根目录,就调用rootProject.file(),如果对应module的目录就直接调用file()。这个方法是对应project目录的相对路径

配置自定义Task

1.简单定义Tasks

这里有两种定义方式

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

两种定义方式的区别是:B会在配置阶段执行,而A需要具体执行A任务或者作为其他任务的依赖才会执行。其实A的这种定义方式将在Gradle 5.0被移除,所以不建议使用了。我们可以通过指定doLast{}来指定。

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

结果:

doFirst
doLast
doLast1
doLast2

指定task的分组和描述

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

我们同步一下,就可以在窗口中发现自定义的分组和描述。
Android Gradle Task使用详解_第2张图片

使用命令行为project传递参数

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

}

在命令行里用驼峰命名执行任务

gradle :app:sP -Ppp=nihao

结果:

nihao
2.使用DefaultTask 添加自定义任务
class IncrementTask extends DefaultTask {

    @TaskAction
    void run() {
        println 'IncrementTask'

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

}

同样我们可以指定分组和描述,在IncrementTask 的构造方法中加入。

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

使用upToDate来跳过任务,我们同样在构造方法中加入。

    outputs.upToDateWhen { true }

这样就可以根据闭包的返回值来判断第二次及以后执行是否需要跳过该任务。

指定任务的输入输出文件以及属性

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

结果:

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.继承原有任务

这里我们使用Gradle插件的Zip任务将apk文件打包到zip包中。在app的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]
    }
}

通过执行这个任务,我们把app\build\outputs\apk\debug下的所有文件打包到了app\build\zip\my.zip中。继承原有任务基本上只要指定输入输出就可以了。
我们可以在gradle-4.4\src\core\org\gradle\api\tasks中倒找部分原有任务。
Android Gradle Task使用详解_第3张图片
里头有copy,delete等等,需要使用可以查看源码。

4.任务依赖

任务之间可以互相依赖,比如让A在B后执行,或者必须让B执行后A才能执行等。主要有下面几种。

relation discirbe
A dependsOn B 指定执行A任务之前必须先执行B任务
A mustRunAfter B 指定B任务在A任务之前执行,但是并不是依赖关系,如果只执行A任务则不需要执行B
A shouldRunAfter B 并行编译下 不一定A在B后面执行
A finalizedBy B 在A执行完后必定会执行B

简单做一个测试

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

结果:

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

在执行MyTask之前,执行了A,然后执行了finalized,然后是B,最后才是MyTask。这里就有一个问题了,MyTask指定的依赖明明是[B,A],然而执行顺序是A->B。这里如果要让B在A以前执行,就需要额外指定A dependsOn B 了。

你可能感兴趣的:(gradle,Gradle学习总结)