Android Gradle学习记录5 Gradle补充说明
2017-09-06 20:14
309 查看
前面的博客已经介绍了Groovy的基本用法及Gradle的工作流程。
通常情况下,我们只需要在当前的编译框架中,增添一些task及函数。
在具备Java基础的前提下,了解Groovy的基本语法后,
完成这部分工作应该还是比较轻松的。
至于解决更复杂的问题,可能就需要进一步学习一些使用实例,
并查询对应的API文档了。
考虑到Gradle整体的知识体系非常庞杂,我暂时也没有能力完全掌握和驾驭,
因此就在这篇文档中补充记录一下Gradle比较零碎的知识和使用实例了。
一、Gradle文件编译后生成的对象
通过前面的博客,我们知道Groovy脚本在编译时,会将脚本的内容转换成Java对象。
Gradle实际上是基于Groovy的,因此Gradle文件编译后也会根据文件的类型生成不同的Java对象。
其中,比较常见的是以下三种对象:
1、Gradle对象
当我们在终端中,利用gradle运行Task时,
gradle会从默认的配置脚本中构造出一个Gradle对象。
在脚本的整个执行过程中,只会有一个Gradle对象,它的数据类型就是Gradle。
一般情况下,我们很少会去定制这个默认的配置脚本。
关于Gradle对象的详细信息及其提供的接口,可以查看对应的文档:
https://docs.gradle.org/current/javadoc/org/gradle/api/invocation/Gradle.html
2、Project对象
在编译时,每一个build.gradle文件都会转化成一个Project对象。
Project对象对应的API文档如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
对于Project对象,我们使用的比较多的是加载插件的接口apply。
根据API文档,我们可以看出Project的apply函数,继承自org.gradle.api.plugins.PluginAware。
对应的API文档如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/plugins/PluginAware.html
对应的描述如下图所示:
我们来看看apply具体的接口定义:
结合上图,我们回忆一下apply通常的用法:
这里之所以着重介绍一下apply接口,主要是想借此来让大家感受下Gradle这个编程框架。
每一行代码,虽然看起来有点像简单的配置或引用,但实际上却是在调用一个实际的接口。
此外,通过这个例子,我们应该学会在必要的时候查询API文档。
Gradle大量的术语及类的介绍,都可以在以下地址找到:
https://docs.gradle.org/current/dsl/
https://docs.gradle.org/current/javadoc/allclasses-noframe.html
3、Settings对象
在编译时,每一个settings.gradle文件都会转化成一个Settings对象。
通常情况下,settings.gradle主要用于指定一个Project包含的子Project,
或定义一些函数,完成初始化时相关的工作。
Settings对象对应的文档地址如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/initialization/Settings.html
4、其它
对于其它的gradle文件,除非定义了class,
否则与普通的Groovy脚本类似,会转换成一个实现了Script接口的对象。
关于整个编译过程中生成对象的顺序,可以参考如下链接:
https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
其中,最主要的部分如下图所示:
可以看出,脚本编译时:
首先生成整个Project对应Settings对象,并按照setting.gradle的定义配置Settings对象;
然后,依据配置的Settings对象,创建出整个Project对象与其子对象的组织结构。
最后,根据settings.gradle中声明的project对应的build.gradle脚本,创建出对应的子Project对象。
由于每个子project都可能有自己的settings.gradle文件,因此还需要继续建立每个子Project的体系结构。
整体而言,这个创建体系结构的过程,是按照广度优先的顺序递归进行的。
二、Gradle中定义额外属性
1、使用方式
Gradle提供了一种名为extra property的方法。
extra property是额外属性的意思,
该属性定义的成员或函数可以被多个Project或Task使用。
在第一次定义该属性的时候,需要通过ext前缀来进行标识,
一旦定义好后,再次使用时就不需要ext前缀了。
Project和Gradle对象均可以设置ext属性。
例如,在一个multi project的工程中,在对应的build.gradle中分别配置子project的属性:
我们在看看其它的用途,比如我们想定义一些工具函数,例如:
此外,利用命令启动编译时,也可以指定额外属性,例如:
2、工具函数的执行特点
至此,我们对extra property有了一定的了解,
其最重要的功能应该还是定义一些工具函数。
提到工具函数,就不得不提一下工具函数执行时的特点。
从上文可以看出工具函数getVersionName中,使用了project对象。
我们知道工具函数定义于buildUtil.gradle文件中,并不归属于任何Project,
那么它使用的project对象到底是什么?
为了搞清楚这个问题,就必须了解函数执行的过程了:
1、当一个 Project apply 一个 gradle 文件的时候, 这个 gradle 文件会转换成一个Script 对象。
2、Script 中有一个 delegate 对象(委托对象), delegate 默认指向加载它的
Project 对象(即调用apply from的Project)。
需要注意的是:
通过 apply to,可以把 delegate 对象指定为别的对象(详情参阅API文档)。
3、当在Script 中操作一些不是 Script 自己定义的变量或者函数时候,
gradle 会到Script的delegate对象去找,看看有没有定义这些变量或函数。
这有点像Android中利用handler处理msg,默认是发送msg的handler处理这个msg,
但设置了callback后,对应的msg将递交给callback处理。
根据上述执行过程,我们知道了:
当其它Project利用apply from加载buildUtil.gradle时,
getVersionName中的project就是加载该文件的Project。
上面的ext就是为对应的Project增加额外属性,
于是Project中的成员就可以使用getVersionName这个函数了。
三、Gradle中的Task
Task是Gradle中的一种数据类型,它代表了一些要执行工作,类似于任务队列中的任务对象。
Project引用不同的插件后,可以添加不同的Task。
每一个Task都需要和一个Project关联。
Project可以管理所有依附自己的Task,例如:。
Task的API文档如下:
https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
1、创建Task的时候可以指定Type,指定新建的Task对象从哪个基类Task派生。
例如:
上述代码就是创建一个Copy Task的子类。
个人觉得,如果新建的Task需要执行的工作,
完全符合某个基类的定义时,才需要指定type,达到简化编码的目的。
即当新建的Task中仅执行copy操作时,才指定type为copy。
如果Task中还有其它的操作,例如调用其它函数,
那么直接继承时,可能由于父类的限制,出现不符合预期的情况。
2、一个Task可包含若干个Action。Action就是一个闭包,用于执行具体的操作。
gradle创建该Task之后,返回给用户之前,
会先执行闭包中的内容。
此外,Task中有doFirst和doLast两个函数,
用于添加需要最先执行的Action和需要最后执行的Action。
整体来讲,task先执行花括号中的内容,
再执行doFirst中的内容,最后执行doLast中的内容。
例如:
执行顺序如下:
需要注意的是,当使用下列方式时,<<符号代表的是doLast:
此时,闭包将作为一个action加入到Task的队列中,最后执行。
通常情况下,我们只需要在当前的编译框架中,增添一些task及函数。
在具备Java基础的前提下,了解Groovy的基本语法后,
完成这部分工作应该还是比较轻松的。
至于解决更复杂的问题,可能就需要进一步学习一些使用实例,
并查询对应的API文档了。
考虑到Gradle整体的知识体系非常庞杂,我暂时也没有能力完全掌握和驾驭,
因此就在这篇文档中补充记录一下Gradle比较零碎的知识和使用实例了。
一、Gradle文件编译后生成的对象
通过前面的博客,我们知道Groovy脚本在编译时,会将脚本的内容转换成Java对象。
Gradle实际上是基于Groovy的,因此Gradle文件编译后也会根据文件的类型生成不同的Java对象。
其中,比较常见的是以下三种对象:
1、Gradle对象
当我们在终端中,利用gradle运行Task时,
gradle会从默认的配置脚本中构造出一个Gradle对象。
在脚本的整个执行过程中,只会有一个Gradle对象,它的数据类型就是Gradle。
一般情况下,我们很少会去定制这个默认的配置脚本。
关于Gradle对象的详细信息及其提供的接口,可以查看对应的文档:
https://docs.gradle.org/current/javadoc/org/gradle/api/invocation/Gradle.html
2、Project对象
在编译时,每一个build.gradle文件都会转化成一个Project对象。
Project对象对应的API文档如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
对于Project对象,我们使用的比较多的是加载插件的接口apply。
根据API文档,我们可以看出Project的apply函数,继承自org.gradle.api.plugins.PluginAware。
对应的API文档如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/plugins/PluginAware.html
对应的描述如下图所示:
我们来看看apply具体的接口定义:
结合上图,我们回忆一下apply通常的用法:
//以下apply调用的是上图中最后一个apply函数 //函数调用时通过 参数名1:参数值1, 参数名2:参数值2 的方式传递参数 //这些参数在传递时,实际上已经被转化为Map类型 apply plugin: 'com.android.library' //除了加载gradle文件外,还能直接加载gradle文件 apply from: rootProject.getRootDir().getAbsolutePath() + '/SDKConfig/checkCode.gradle'
这里之所以着重介绍一下apply接口,主要是想借此来让大家感受下Gradle这个编程框架。
每一行代码,虽然看起来有点像简单的配置或引用,但实际上却是在调用一个实际的接口。
此外,通过这个例子,我们应该学会在必要的时候查询API文档。
Gradle大量的术语及类的介绍,都可以在以下地址找到:
https://docs.gradle.org/current/dsl/
https://docs.gradle.org/current/javadoc/allclasses-noframe.html
3、Settings对象
在编译时,每一个settings.gradle文件都会转化成一个Settings对象。
通常情况下,settings.gradle主要用于指定一个Project包含的子Project,
或定义一些函数,完成初始化时相关的工作。
Settings对象对应的文档地址如下:
https://docs.gradle.org/current/javadoc/org/gradle/api/initialization/Settings.html
4、其它
对于其它的gradle文件,除非定义了class,
否则与普通的Groovy脚本类似,会转换成一个实现了Script接口的对象。
关于整个编译过程中生成对象的顺序,可以参考如下链接:
https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
其中,最主要的部分如下图所示:
可以看出,脚本编译时:
首先生成整个Project对应Settings对象,并按照setting.gradle的定义配置Settings对象;
然后,依据配置的Settings对象,创建出整个Project对象与其子对象的组织结构。
最后,根据settings.gradle中声明的project对应的build.gradle脚本,创建出对应的子Project对象。
由于每个子project都可能有自己的settings.gradle文件,因此还需要继续建立每个子Project的体系结构。
整体而言,这个创建体系结构的过程,是按照广度优先的顺序递归进行的。
二、Gradle中定义额外属性
1、使用方式
Gradle提供了一种名为extra property的方法。
extra property是额外属性的意思,
该属性定义的成员或函数可以被多个Project或Task使用。
在第一次定义该属性的时候,需要通过ext前缀来进行标识,
一旦定义好后,再次使用时就不需要ext前缀了。
Project和Gradle对象均可以设置ext属性。
例如,在一个multi project的工程中,在对应的build.gradle中分别配置子project的属性:
//subprojectA和subprojectB均为multi project的子project .............. project(':subprojectA') { //gradle指的是gradle对象,默认是Settings和Project对象的成员变量 //gradle可以直接通过ext前缀操作外置属性 //这里新建了一个version的外置属性 gradle.ext.version = '1.0' } project(':subprojectB') { //由于version是基于gradle对象的外置属性 //同时整个工程只有一个gradle对象 //因此subprojectB中也可以获取该对象的成员 //再次使用时,不需要再使用ext前缀了 println gradle.version } .............
我们在看看其它的用途,比如我们想定义一些工具函数,例如:
//在工具函数对应的文件,例如buildUtil.gradle中, //将定义的函数添加到ext闭包中 //对应的函数就会成为额外属性的一部分 //当其他的Project利用apply from添加buildUtil.gradle时, //就可以使用这些函数了 ext { getVersionName = this.&getVersionName } def getVersionName() { def xmlFile = project.file("AndroidManifest.xml") ................ }
此外,利用命令启动编译时,也可以指定额外属性,例如:
//这里为整个工程增加了额外属性packageName,对应的值为test //这样就实现了将参数传递到编译脚本的工作 ./gradlew clean buildSdk -PpackageName=test
2、工具函数的执行特点
至此,我们对extra property有了一定的了解,
其最重要的功能应该还是定义一些工具函数。
提到工具函数,就不得不提一下工具函数执行时的特点。
从上文可以看出工具函数getVersionName中,使用了project对象。
我们知道工具函数定义于buildUtil.gradle文件中,并不归属于任何Project,
那么它使用的project对象到底是什么?
为了搞清楚这个问题,就必须了解函数执行的过程了:
1、当一个 Project apply 一个 gradle 文件的时候, 这个 gradle 文件会转换成一个Script 对象。
2、Script 中有一个 delegate 对象(委托对象), delegate 默认指向加载它的
Project 对象(即调用apply from的Project)。
需要注意的是:
通过 apply to,可以把 delegate 对象指定为别的对象(详情参阅API文档)。
3、当在Script 中操作一些不是 Script 自己定义的变量或者函数时候,
gradle 会到Script的delegate对象去找,看看有没有定义这些变量或函数。
这有点像Android中利用handler处理msg,默认是发送msg的handler处理这个msg,
但设置了callback后,对应的msg将递交给callback处理。
根据上述执行过程,我们知道了:
当其它Project利用apply from加载buildUtil.gradle时,
getVersionName中的project就是加载该文件的Project。
上面的ext就是为对应的Project增加额外属性,
于是Project中的成员就可以使用getVersionName这个函数了。
三、Gradle中的Task
Task是Gradle中的一种数据类型,它代表了一些要执行工作,类似于任务队列中的任务对象。
Project引用不同的插件后,可以添加不同的Task。
每一个Task都需要和一个Project关联。
Project可以管理所有依附自己的Task,例如:。
//查找project中所有名称包含Debug的Task //返回值保存到targetTasks容器中 def targetTasks = project.tasks.findAll{task -> task.name.contains("Debug") } //对满足条件的task, 设置它为disable, 于是这个Task就不会被执行 targetTasks.each{ println "disable debug task: ${it.name}" it.setEnabled false }
Task的API文档如下:
https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
1、创建Task的时候可以指定Type,指定新建的Task对象从哪个基类Task派生。
例如:
task copyClasses(type: Copy) { ......... }
上述代码就是创建一个Copy Task的子类。
个人觉得,如果新建的Task需要执行的工作,
完全符合某个基类的定义时,才需要指定type,达到简化编码的目的。
即当新建的Task中仅执行copy操作时,才指定type为copy。
如果Task中还有其它的操作,例如调用其它函数,
那么直接继承时,可能由于父类的限制,出现不符合预期的情况。
2、一个Task可包含若干个Action。Action就是一个闭包,用于执行具体的操作。
//花括号是一个闭包。 task myTask { xxxxxx }
gradle创建该Task之后,返回给用户之前,
会先执行闭包中的内容。
此外,Task中有doFirst和doLast两个函数,
用于添加需要最先执行的Action和需要最后执行的Action。
整体来讲,task先执行花括号中的内容,
再执行doFirst中的内容,最后执行doLast中的内容。
例如:
task test1() { doFirst { println "test1 doFirst" } println "test1 closure" doLast { println "test1 doLast" } } //test1执行完后,才执行test2 //不过花括号中的内容:println "test2 closure" //在创建后,返回前就执行了 task test2(dependsOn: test1) { doFirst { println "test2 doFirst" } println "test2 closure" doLast { println "test2 doLast" } }
执行顺序如下:
test1 closure test2 closure test1 doFirst test1 doLast test2 doFirst test2 doLast
需要注意的是,当使用下列方式时,<<符号代表的是doLast:
task myTask << { xxx }
此时,闭包将作为一个action加入到Task的队列中,最后执行。
相关文章推荐
- Android Gradle学习记录6 代码记录(持续补充)
- Android Gradle学习记录2 类及脚本的特点
- Android Gradle学习记录4 Gradle概念及工作流程
- Android Gradle学习记录1 基本特点
- Android Gradle学习记录3 Groovy处理文件
- 黑马程序员Java培训、Android培训-Java 学习过程记录_面向对象上2
- 黑马程序员Java培训、Android培训-Java 学习过程记录_面向对象下
- 黑马程序员Java培训、Android培训-Java 学习过程记录_多线程
- 黑马程序员Java培训、Android培训-Java 学习过程记录_面向对象下2
- 黑马程序员Java培训、Android培训-Java 学习过程记录_JavaAPI-1
- 黑马程序员Java培训、Android培训-Java 学习过程记录_多线程2
- Android 学习记录—新家
- android 学习记录—————Handler的使用
- Android JNI学习之第一个入门实例(确实花了不少功夫,也遇到了很多阻碍,不过还好,最终解决,记录下)
- android数据存储学习记录
- android数据存储学习记录
- 黑马程序员Java培训、Android培训_Java 学习过程记录_语言基础2
- [android学习记录]
- Android学习资源(持续补充)
- NUnit学习 -标签、方法 记录与说明