Gradle入门

相关文档
http://www.groovy-lang.org/groovy-dev-kit.html
http://www.groovy-lang.org/api.html

基本复制此篇文档,我是作为笔记学习的形式做记录
https://www.cnblogs.com/leipDao/p/10385155.html

目录

Gradle实战.png

Groovy学习

Groovy是一门jvm语言,最终编译成class文件然后在jvm上执行,Java语言的特性Groovy都支持,我们可以混写JavaGroovy,就是在同一文件中可以混写, 注意,这里与JavaKotlin可不一样,JavaKotlin是可以互相调用,而不能在同一文件混写 。

Groovy的优势是什么呢?Groovy增强了Java的很多功能。比如解析xml文件,文件读写等,Groovy只需要几行代码就能搞定,而如果用Java则需要几十行代码,简单说就是使用Groovy实现某些功能比Java要少些很多代码。

基本语法

声明变量

Groovy使用def来声明变量,声明变量可以不加类型,运行的时候可以自动推断出变量类型,并且声明语句可以不加分号结尾

def  i = 10
def  str = "hello groovy"
def  d = 1.25
声明方法

def同样用来定义函数,Groovy中函数返回值可以是无类型的:

//定义函数
def showName(){
    "wang lei" //最后一行执行结果默认作为函数返回值,可以不加return
}

如果我们指定了函数的返回值类型,那么可以不加def关键字:

//定义函数
String showName(){
    "wang lei" //最后一行执行结果默认作为函数返回值
}
字符串

Groovy中字符串分为三种,我们一个个来看。
单引号字符串,单引号字符串不会对$进行转义,原样输出

def i = 10
def str1 = 'i am $i yuan'
println str1 

输出 i am $i yuan

双引号字符串,双引号字符串会对$号进行转义,如下:

def i = 10
def str2 = "i am $i yuan"
println str2 

输出 i am 10 yuan

三引号字符串,三引号字符串支持换行,原样输出,如下:

def str3 = '''
   public static void main(){
       println "miss you"
   }
'''
println str3

输出

def str3 = '''
   public static void main(){
       println "miss you"
   }
数据类型

Groovy数据类型主要包括以下三种:
1.Java中基本数据类型
2.增强的List,Map,Range容器类
3.闭包

我们分别看一下

Java中基本数据类型

Groovy中的所有事物都是对象。intdoubleJava中的基本数据类型,在Groovy中对应的是它们的包装数据类型。比如int对应为Integer。比如:

def x = 23
println x.getClass().getCanonicalName()

def f = true
println f.getClass().getCanonicalName()

结果:
java.lang.Integer
java.lang.Boolean

增强的List,Map,Range容器类
List

List:链表,其底层对应Java中的List接口,一般用ArrayList作为真正的实现 类。
使用如下:

def myList = [5,'werw',true]//看到了吧,可以放任意数据,就是那么任性
myList.add(34)
//myList.add(12,55)//这样会报角标越界异常
myList[6] = true
println myList.size()
//遍历
myList.each{
   println "item: $it"
}
myList.eachWithIndex {
   it, i -> // `it` is the current element,`i` is the index
   println "$i: $it"
}
println myList.getClass().getCanonicalName()

结果:

7
item: 5
item: werw
item: true
item: 34
item: null
item: null
item: true
0: 5
1: werw
2: true
3: 34
4: null
5: null
6: true
java.util.ArrayList

看到了吧,GroovyList用起来方便多了,扩展了Java中的一些功能。
单独说明一下,List还有一种方式可以加入元素:<<操作。如下:

myList << 34

刚接触是不是感觉很别扭,慢慢来,习惯就好了,对于<<文档描述如下:

<<.png

文档地址:http://www.groovy-lang.org/groovy-dev-kit.html与 http://www.groovy-lang.org/api.html 建议还是浏览一下文档,里面有很多好玩的东西

Map

直接看示例:

//Map类
def map = ['key1':true,name:"str1",3:"str3",4:"str4"]
println map.name // 相当于 map.get('name')
println map.get(4)
map.age = 14 //加入 age:14 数据项
println map.age //输出14
println map.getClass().getCanonicalName()
//遍历
map.each{
    key,value ->
        println key +"--"+ value
}

map.each{
    it ->
        println "$it.key ::: $it.value"
}
// `entry` is a map entry, `i` the index in the map
map.eachWithIndex { entry, i ->
    println "$i - Name: $entry.key Age: $entry.value"
}

// Key, value and i as the index in the map
map.eachWithIndex { key, value, i ->
    println "$i - Name: $key Age: $value"
}

println map.containsKey('key1')  //判断map中是否包含给定的key
println map.containsValue(1)  //判断map中是否包含给定的value
//返回所有
println map.findAll{
    entry ->
        entry.value instanceof String//value是String类型的
}
//返回第一个符合要求的
println map.find{
    entry ->
        entry.key instanceof Integer && entry.key > 1
} //返回符合条件一个entry

//清空
map.clear()

结果:

str1
str4
14
java.util.LinkedHashMap
key1--true
name--str1
3--str3
4--str4
age--14
key1 ::: true
name ::: str1
3 ::: str3
4 ::: str4
age ::: 14
0 - Name: key1 Age: true
1 - Name: name Age: str1
2 - Name: 3 Age: str3
3 - Name: 4 Age: str4
4 - Name: age Age: 14
0 - Name: key1 Age: true
1 - Name: name Age: str1
2 - Name: 3 Age: str3
3 - Name: 4 Age: str4
4 - Name: age Age: 14
true
false
{name=str1, 3=str3, 4=str4}
3=str3
0
Ranges

关于Ranges文档描述如下:

Range.png

简单来说Ranges就是对List的扩展,用..或者..<来定义,具体使用如下:

//Range
def Range1 = 1..10//包括10
println Range1.contains(10)
println Range1.from +"__"+Range1.to
def Range2 = 1..<10//不包括10
println Range2.contains(10)
println Range2.from +"__"+Range2.to
//遍历
for (i in 1..10) {
   println "for ${i}"
}

(1..10).each { i ->
   println "each ${i}"
}
def years = 23
def interestRate
switch (years) {
   case 1..10: interestRate = 0.076; break;
   case 11..25: interestRate = 0.052; break;
   default: interestRate = 0.037;
}
println interestRate//0.052

结果:

true
1__10
false
1__9
for 1
for 2
for 3
for 4
for 5
for 6
for 7
for 8
for 9
for 10
each 1
each 2
each 3
each 4
each 5
each 6
each 7
each 8
each 9
each 10
0.052

以上就是Groovy中的容器类

Groovy中的闭包

闭包Closure一开始接触的时候真是有点蒙圈的感觉,这是什么玩意,Kotlin中也有这玩意,接触多了也就慢慢习惯了,其实就是一段可执行的代码,我们可以像定义变量一样定义可执行的代码。
闭包一般定义如下:

def xxx = {
    paramters ->
        code
}

比如,我们定义一下闭包:

def mClosure = {
    p1,p2 ->
         println p1 +"..."+p2
}

p1,p2也可以指定数据类型,如下:
//闭包定义
//->前是参数定义, 后面是代码

def mClosure = {
   String p1, int p2 ->
        println p1 +"..."+p2
}

调用上述定义的闭包:

//调用 均可以
mClosure("qwewe",100)
mClosure.call("qwewe",100)

看到这里有C经验的是不是瞬间想到函数指针了,连调用都非常像。

定义闭包我们也可以不指定参数,如不指定则默认包含一个名为it的参数:

def hello = { "Hello, $it!" }
println hello("groovy")

结果:Hello, groovy!

关于闭包,刚接触肯定不习惯,自己一定要花时间慢慢体会,闭包在Gradle中大量使用,后面讲Gradle的时候会大量接触闭包的概念。

读文件

读文件有三种操作:一次读取一行,读取全部返回字节数据,数据流的形式读取,我们分别看一下:

一次读取一行:

def src = new File("/Users/yanpengfei/Desktop/in.txt")
//每次读取一行
src.eachLine{
        //it就是每一行数据
    it ->
        println it
}

文件内容:


文件内容.png

结果:

1
2
3
4
5
6

读取全部返回字节数据:

def src = new File("/Users/yanpengfei/Desktop/in.txt")

 //一次读取全部:字节数组
def bytes = src.getBytes()
def str = new String(bytes)
println "str::"+str

结果:

str::1
2
3
4
5
6

数据流的形式读取:

def src = new File("/Users/yanpengfei/Desktop/in.txt")

//返回流,不用主动关闭
src.withInputStream{
    inStream ->
        //操作。。。。
        println "inStream::"+inStream
}

结果:inStream::java.io.BufferedInputStream@2106a180

看到这里是不是不禁感叹:so easy!!!。是的,GroovyIO操作就是那么潇洒,任性。

写文件

写文件的操作同样很简单,我们看下将in.txt文件拷贝到out.txt中怎么操作:

//写数据
def des = new File("/Users/yanpengfei/Desktop/out.txt")
des.withOutputStream{
    os->
        os.leftShift(bytes)//左移在这里可以起到写入数据的作用
}

我们也可以逐行写入数据:

//写数据
def des = new File("/Users/yanpengfei/Desktop/out.txt")
des.withWriter('utf-8') { writer ->
    writer.writeLine 'i'
    writer.writeLine 'am'
    writer.writeLine 'wanglei'
}

结果:


结果.png

我们也可以这样写入数据:

des << '''i love groovy'''

IO操作就是这么简单

XML解析

同样我电脑有如下xml文档:

文档.png


   
       
           
               zhangsan
               12
           
           
               lisi
               23
           
       
   

Groovy解析xml文档同样非常简单,我们可以像操作对象一样操作xml

//xml解析
def xmlFile = new File("/Users/yanpengfei/Desktop/test.xml")
def parse = new XmlSlurper()
def result =parse.parse(xmlFile)

def p0 = result.value.persons.person[0]
println p0['@id']
println p0.name
println p0.age

备注:我的Gradle版本'gradle-7.3.3-bin',找不到XmlSlurper类所以没法做测试,后续解决了再替换这里

Json

直接看代码吧,很简单:

//Person类
class Person{
   def first
   def last
}

def p = new Person(first: 'wanglei',last: '456')
//转换对象为json数据
def jsonOutput = new JsonOutput()
def json = jsonOutput.toJson(p)
println(json)
//格式化输出
println(jsonOutput.prettyPrint(json))

//解析json
def slurper = new JsonSlurper()
Person person = slurper.parseText(json)
println person.first
println person.last

打印输出如下:

{"first":"wanglei","last":"456"}
{
   "first": "wanglei",
   "last": "456"
}
wanglei
456

好了,以上就是Groovy的一些核心了,对于学习Gradle掌握上面这些就差不多了。下面进入Gradle的学习。

认识Gradle

Gradle到底是个什么玩意?为什么要先抛出这个问题,从我经验来说,大量开发者都只是会配置Gradle,配置这个,配置那个,至于为什么这么配置,出了问题怎么查找等等完全扒瞎,很多开发者都仅仅停留在配置这个阶段,我认为Gradle的学习有三个层次:简单配置->认为Gradle是个脚本工具->Gradle同样是编程框架。

我个人更倾向认为Gradle是一个编程框架,其实无论你认为是框架还是脚本,只要能够为我所用即可。

Gradle学习主要参考文档如下:

Gradle API:https://docs.gradle.org/current/javadoc/org/gradle/api/package-summary.html

Gradle DSL:https://docs.gradle.org/current/dsl/org.gradle.api.Project.html

Gradle用户手册:https://docs.gradle.org/current/userguide/userguide.html

Android插件DSL参考:http://google.github.io/android-gradle-dsl/current/index.html

到这里可能你还有点蒙圈,一看文档这都是什么玩意啊,别着急,一步步来慢慢认识Gradle。

Gradle环境搭建

安装Gradle开发环境很简单,参考官方文档即可:安装Gradle
安装Gradle前最好将JDK先升级到1.8版本,Gradle最新版本需要的JDK版本为1.8

请自行安装好Gradle环境。

初识Gradle

Gradle是一个开源的构建自动化工具,既然是用于项目构建,那它肯定要制定一些规则,在Gradle中每一个待编译的工程都称为Project,每个Project都可以引入自己需要的插件,引入插件的目的其实就是引入插件中包含的Task,一个Project可以引入多个插件,每个插件同样可以包含一个或多个Task,关于插件和Task我们后面还会单独细说。

比如,如下项目:


项目.png

工程GradleLearn包含三个module:app,library1,library2。其中appApp module,而library1library2均是library module

相信现在大部分都是这种多module项目了,对于Gradle来说这种叫做multiprojects,看这意思是多projects的项目,那么对于Gradle来说有多少个项目呢?

我们可以通过gradle projects命令来查看有多少个projects

image.png

这里我是在命令行里执行的。

备注:报错bash gradle command not found
解决办法:https://juejin.cn/post/6995473605966430245

报错: Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
解决办法:https://www.cjavapy.com/article/91/

看到了吧,对于Gradle来说有4project,其中GradleLearn叫做Root project,其余三个moudule均叫做Project

Gradle怎么知道有多少个Project呢?在我们创建工程的时候在根目录下有个settings.gradle文件,我们看下其中内容:

include ':app', ':library1', ':library2'

默认只有app模块,之后我们新建的library1,library2模块都会自动包含进来,Gradle就是通过查看这个配置文件来确定我们工程有多少了project的,我们修改settings.gradle文件:

include ':app', ':library1'

去掉library2模块,然后在执行gradle projects命令,如下:

image.png

看到了吧,已经没有library2模块了。

好了,现在我们对settings.gradle有了初步的认识,我们在看看build.gradle文件的作用,工程根目录下有个build.gradle,每个module下也有自己的build.gradle文件:

image.png

记得刚接触Gradle的时候这几个build.gradle文件真是让我蒙圈,怎么这么多,都干什么的,相信很多同学刚开始都有这疑问。

上面我们提到GradleLearn叫做Root project,其余三个moudule均叫做Project,其实在GradleGradleLearn被当做三个module的父级project,在父projectbuild.gradle中配置的信息可以作用在子project中,比如根目录build.gradle内容如下:

..........
allprojects {
   repositories {
       google()
       jcenter()
   }
}
.........

这里的意思就是配置此项目及其每个子项目的仓储库为google()jcenter(),这样我们就不用在每个子projectbuild.gradle中再单独配置了,否则我们需要为每个子project单独配置一下需要引入的插件的仓储库。

projectbuild.gradle文件并不是必须的,我们甚至可以删除掉,其存在的意义主要就是将子project公共的配置提取到父build.gradle来统一管理,是不是有点像“基类”的意思。

好了,以上只是大概了解了一下settings.gradlebuild.gradle,都是及其简单的。

settings.gradlebuild.gradle的本质

大家有没有想过这样一个问题为什么settings.gradle可以include子模块,又为什么build.gradle可以写如下配置呢:

buildscript {
   repositories {
       google()
       jcenter()
   }
   dependencies {
       classpath 'com.android.tools.build:gradle:3.3.1'
   }
}

allprojects {
   repositories {
       google()
       jcenter()
   }
}

task clean(type: Delete) {
   delete rootProject.buildDir
}

其实我们在settings.gradlebuild.gradle中看似配置的信息其实都是调用对应对象的方法或者脚本块设置对应信息。

对应对象是什么玩意?其实settings.gradle文件最终会被翻译为Settings对象,而build.gradle文件最终会被翻译为Project对象,build.gradle文件对应的就是每个project的配置。

SettingsProjectGradle中都有对应的类,也就是说只有Gradle这个框架定义的我们才能用,至于SettingsProject都定义了什么我们只能查看其官方文档啊。

Settings对象

比如Settings类中定义了include方法:

Settings.png

include方法api说明为:

include.png

看到了吧,我们每一个配置都是调用对应对象的方法。

我还发现Settings类中定义了如下方法:

Settings.png

include ':app', ':library1', ':library2'

def pro = findProject(':app')
println '----------------------------'
println pro.getPath()
println '----------------------------'

然后执行gradle assembleDebug命令编译我们的项目输出如下:

image.png

输出了app这个project的信息。

Project对象

每个build.gradle文件都会被翻译为对应的Project对象,build.gradle文件最重要的作用就是:
引入插件并配置相应信息
添加依赖信息
引入插件重要的就是引入插件中包含的tasks,至于插件与tasks后面会详细讲到。
那怎么引入插件呢?
Project定义了apply函数供我们调用:

apply.png

平时我们看到的如下:

apply plugin: 'com.android.library'

最终都是调用那个的上面apply方法。
Project类中有个很重要的方法,如下:

image.png

这个方法在配置完当前project后立刻调用,并且传给我们project参数,我们调用试试,在根build.gradle中添加如下代码:

afterEvaluate{
    project ->
        println "root module -----> $project.name"
}

app modulebuild.gradle添加如下代码:

afterEvaluate{
    project ->
    println "app module -----> $project.name"
}

同样,执行gradle assembleDebug命令,打印如下:

运行结果.png

Gradle有它自己的规则,怎么配置,配置什么都在文档中有对应规定,我们配置xxx.gradle都有对应的类,最终都翻译成对应对象,有问题查阅相关文档即可。

Gradle对象

在我们执行gradle相关命令的时候,Gradle框架会为我们创建一个gradle对象,并且整个工程只有这一个gradle对象,这个对象不像上面两个一样有对应文件,这个对象一般不需要我们配置什么,主要用于给我们提供一些工程信息,具体有哪些信息呢?查看文档中Gradle类包含以下信息:

image.png

我们可以打印一些信息看看,在根build.gradle中添加如下代码:

println "homeDir = $gradle.gradleHomeDir"
println "UserHomeDir = $gradle.gradleUserHomeDir"
println "gradleVersion = $gradle.gradleVersion"

执行gradle assembleDebug命令打印如下信息:

image.png

gradle对象最重要的就是在构建工程的时候加入各种回调,通过加入回调我们可以监听工程构建的各个时期,这部分后面会讲到。

好了,到这里Gradle主要的三个类就基本介绍完了,至于每个类定义了什么属性,方法等等还需要自己去看看文档。

Gradle工作时序

Gradle执行分为三个过程:

Initiliazation

初始化阶段只要为每个module创建project实例。这个阶段settings.gradle文件会被解析执行。

Configration

这个阶段解析每个模块的build.gradle文件,这个阶段完成后整个项目的tasks执行顺序也就确定了并且task准备就绪处于待执行状态,整个tasks任务会构成一个有向无环图。

执行任务

这阶段就是按照顺序执行具体任务了。
在每个阶段我们可以通过gradle对象添加回调监听。
我们在settings.gradle文件与每个modulebuild.gradle文件添加如下信息:

settings.gradle:
println "settings start"
rootProject.name = "Gradle Accidence"
include ':app'
include ':mylibrary1'
include ':mylibrary2'
println "settings end"
根目录的build.gradle

通过gradle对象添加了一些回调监听

afterEvaluate{
    project ->
        println "root module afterEvaluate -----> $project.name"
}

gradle.beforeProject{
    project ->
        println "beforeProject $project.name"
}

gradle.afterProject{
    project ->
        println "afterProject $project.name"
}

gradle.taskGraph.whenReady {
    println "taskGraph.whenReady"
}

gradle.buildFinished{
    result ->
        println "buildFinished"
}
app module的build.gradle:
println "app start"
afterEvaluate{
    project ->
        println "app module afterEvaluate -----> $project.name"
}
println "app end"
library1 module的build.gradle:
println "library1 start"
afterEvaluate{
    project ->
        println "library1 module afterEvaluate -----> $project.name"
}
println "library1 end"
library2 module的build.gradle:
println "library2 start"
afterEvaluate{
    project ->
        println "library2 module afterEvaluate -----> $project.name"
}
println "library2 end"

接下来我们执行gradle assembleDebug命令,打印如下信息:

运行结果.png

以上就是Gradle构建工程的大体过程,在这个过程我们可以加入各种回调监听。

Gradle中的task

task可以说Gradle中很重要的部分,taskGradle的执行单元,一个task就是具体执行某一任务。

AS中我们一创建工程的时候就存在很多task

任务.png

这些task都是我们引入安卓插件帮我们自动引入的,关于插件马上就讲到了。

自定义task
我们可以定义自己的task,在app模块的build.gradle中添加如下代码:

task aTask{
    println ">>>>>>>>>>>>>>>>task..."
}

这样我们就定义了名称为aTask的任务了,在AS中同步之后我们可以看到:

任务.png

由于我们没有指明分组所以这里默认属于other分组,我们可以指定自己的分组:

task aTask(group:'myGroup'){
    println ">>>>>>>>>>>>>>>>task..."
}

同步之后,如下:

image.png

上面我们说过build.gradle对应Gradle中的Project类,Project类中定义了如下方法:

Project类.png

正式由于Project类中定义了上面方法,我们才可以以上面方式来创建task任务。
我们可以通过gradle task名称的命令来执行某一个task任务,比如执行上述任务:gradle aTask

image.png

上述打印信息的代码是在Configure阶段来执行的,也就是我们可以提前配置一下我们的task,如果我们不需要配置想在执行我们task的时候来执行一些操作,我们也可以修改代码如下:

task aTask(group:'myGroup'){
   println ">>>>>>>>>>>>>>>>config..."
   //任务开始执行初期执行
   doFirst{
       println ">>>>>>>>>>>>>>>>aTask doFirst..."
   }
   //任务开始执行末期执行
   doLast{
       println ">>>>>>>>>>>>>>>>aTask doLast..."
   }
}

执行gradle aTask命令来执行任务:

运行结果.png

此外,有时我们也会看到如下写法:

task B << {
    println 'B'
}

这种写法和如下写法都是一样效果:

task B {
    doLast {
        println 'B'
    }
}

备注:此种方式,我测试时报错的

task B << {
    println 'B'
}
task的依赖关系

task之间可以指定依赖关系,比如指定A task依赖B task那么在执行A task的时候需要先执行B task,我们修改代码如下:

task aTask(group:'myGroup'){
    println ">>>>>>>>>>>>>>>>a config..."

    doFirst{
        println ">>>>>>>>>>>>>>>>aTask doFirst..."
    }

    doLast{
        println ">>>>>>>>>>>>>>>>aTask doLast..."
    }
}

task bTask(group:'myGroup'){
    println ">>>>>>>>>>>>>>>>b config..."

    doFirst{
        println ">>>>>>>>>>>>>>>>bTask doFirst..."
    }

    doLast{
        println ">>>>>>>>>>>>>>>>bTask doLast..."
    }
}
//这里指定aTask 依赖于bTask
aTask.dependsOn bTask

运行结果:


image.png

我们也可以创建task的时候就直接指定依赖:

//通过dependsOn指定依赖
task aTask(group:'myGroup', dependsOn: ["bTask"]){
    println ">>>>>>>>>>>>>>>>a config..."

    doFirst{
        println ">>>>>>>>>>>>>>>>aTask doFirst..."
    }

    doLast{
        println ">>>>>>>>>>>>>>>>aTask doLast..."
    }
}

task bTask(group:'myGroup'){
    println ">>>>>>>>>>>>>>>>b config..."

    doFirst{
        println ">>>>>>>>>>>>>>>>bTask doFirst..."
    }

    doLast{
        println ">>>>>>>>>>>>>>>>bTask doLast..."
    }
}

运行结果:


运行结果.png

二者同样效果

我们也可以定义task类,此类需要继承DefaultTask

class IncrementTask extends DefaultTask {

    @Input
    String msg = 'default'

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

    @TaskAction
    void run() {
        println "IncrementTask __$msg"
    }
}

上面用@TaskAction标注方法run(),这样我们在执行任务的时候会调用run()方法。
接下来我们可以通过如下方式创建实例:

task increment2(type: IncrementTask) {
    msg = 'create task'
}

创建task的时候我们可以指定type,也就是指定其父类,如果我们不制定默认为DefaultTask的子类。
我们也可以通过如下方式创建:

tasks.create('increment1', IncrementTask){
    msg = 'tasks.create'//重新指定msg信息
}

这里我在说一下查文档的重要性,tasks是什么鬼?由于我们是在build.gradle中使用的,其对应Project类,所以我们去Project类中查一下,属性描述有对其描述:

tasks.png

原来tasks是一个属性,点进去看一下:

tasks.png

其对应的是TaskContainer类,我们还需要再看一下这个类都包含什么:

TaskContainer.png

看到了吧,这个类中包含各种create方法用来创建task任务。

好了,task就说这么多,有什么问题希望你自己去查文档解决,比如创建的时候可以指定type,那还可以指定其余的信息吗?都可以指定什么信息,这些文档中都有描述。

Gradle中任务的增量构建

作为构建工具我们要防止做重复工作。例如AS编译出APK文件,如果我们已经编译出了APK文件,再次编译的时候如果我们没有删除APK文件并且代码资源等都没变化那么就没必要在重新走一遍流程执行各个task任务最重输出APK文件,中间的任务都可以跳过,这样可以提升效率缩短编译时间。

Gradle是通过增量构建的特性来支持这个功能的。

Gradle在执行任务的时候会检查任务的输入输出是否有变化,如果任务的输入输出均没有变化则认为任务是up-to-date的,会跳过任务不去执行它,任务至少有一个输出否则增量构建不起作用。

我们改造IncrementTask,使其成为可以增量构建的任务,指明其输入输出:

class IncrementTask extends DefaultTask {

    @Input //指明输入
    String msg = 'default'

    @OutputFile //指明输出
    File file

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

    @TaskAction
    void run() {
        println "IncrementTask __$msg"
    }
}

我们在创建任务的时候指明其输入输出:

tasks.create('increment1', IncrementTask){
    msg = 'tasks.create1'//重新指定msg信息
    file = file('path.txt')
}

我们在第一次执行任务的时候,输出如下:

结果.png

执行了run方法输出相应信息,接着我们再次执行:

结果.png

看到了吧,没有执行run方法,并且提示:up-to-date

我们也可以关闭任务的增量构建,使其每次执行的时候都会执行run方法:

class IncrementTask extends DefaultTask {

    @Input //指明输入
    String msg = 'default'

    @OutputFile //指明输出
    File file

    IncrementTask() {
        group '自定义任务'
        description '任务描述'
        outputs.upToDateWhen { false }//返回false关闭增量构建
    }

    @TaskAction
    void run() {
        println "IncrementTask __$msg"
    }
}

tasks.create('increment1', IncrementTask){
    msg = 'tasks.create1'//重新指定msg信息
    file = file('path.txt')
}

每次执行结果:


结果.png

增量构建功能主要是为了提升编译效率,否则一个大的项目包含几十几百的任务不能每次编译都要挨个重新执行每次任务吧,这里只是简单介绍了一下Gradle的增量构建功能,详细学习可以自己查阅文档看一下。

自定义插件

暂不学了,学一下groovy语法,解决pod问题,后面有时间再学习插件

你可能感兴趣的:(Gradle入门)