每一个Gradle的构建都是从一个脚本开始的,构建脚本的默认名字是build.gradle,当在shell中执行gradle命令时,Gradle就会去寻找这个build.gradle的文件。如果找不到就会显示一个帮助信息。
在app文件下的build.gradle文件中定义一个原子工作,在上图中 task在Gradle中就是构建一个任务,这个任务是输出helloworld,下面在Terminal执行gradle hello(gradle taskname
):
通过gradle -q hello可以加快执行速度(通过命令选项quiet,只需执行里面代码,省去了一些记录别的东西的操作)
task和里面的action是groovy这门语言的重要元素,doLast就是一个action,表示这个action最后执行,也可以用 符号<<来表示doLast:
下面展示Gradle更高级的特性:
代码中 dependsOn
来说明task之间的依赖。
Gradle会确保被依赖的task总会在定义该依赖的task之前执行。
dependsOn是task的一个方法,比如我们执行最后一行的groupThreapy,它里面依赖了mGradle2,所以会先执行mGradle2,但是mGradle2又依赖了mGradle1和mGradle0,所以在执行mGradle2前会先执行mG1和mG0,而mG0依赖了startTaskeone,所以最开始就会先执行startTaskone。
Gradle可以很好的和Ant(是一个java的构建工具)去集成,因为拥有对Groovy语言特性的完全访问权,所以用write()来打印信息。每个脚本都带有一个ant属性,赋予了可以直接访问Ant任务的能力。上面的例子中可以使用Ant的任务echo去打印"Gradle"。
另外Gradle提供的一个特性就是定义动态task,就是指向运行中指定任务的名字。在上述例子中,使用了Groovy的times方法创建了3个task。Groovy自动暴露一个隐式变量it来指定循环迭代的次数,可以使用这个计数器来构建task的名字,对于第一次循环的task叫做mGradle0.
下面运行 grade groupTherapy:
从上面结果可以看出执行过程:
- 通过执行
gradle -q tasks
:列出项目中所有可用的task:
这个时候可能会产生:构建脚本中定义的其他task去哪了?
- 通过执行
gradle -q tasks --all
就可以列出项目内所有的task信息
在Other task中,就有这些定义的task啦(group Threapy、mGradle0…):
任务名字缩写
gradle另外一个特性就是能以驼峰式的缩写在命令行上运行任务,例如在上述例子中,可以执行
gradle mG0 gT一样可以运行:
当然如果出现两个相同缩写的方法,比如写一个gotest和groupThreapy缩写相同,则执行命令行会报错。
执行时排除任务
有时候在构建运行时,需要排除一个指定任务,这时候可以通过-x
来实现,假设现在要排除mGradle0:
命令行选项:
-
gradle xxxx -is
或者gradle xxxx -i-s
:打印出构建期间时的发生错误的堆栈追踪痕迹 -
gradle xxxx --help
:打印出所有可用的命令行选项,描述信息 -
gradle -b xxx.gradle
:可以执行一个特定的名字的构建脚本 -
gradle xxxx --offline
:离线模式运行构建,仅仅在本地缓存检查依赖是否存在
守护进程:
当每次和gradle打交道的时候,会发现我们每次都需要不断重复构建,每次初始化一个构建时,JVM都要重启一次,Gradle的依赖都要载入到类加载器中,而且还要建立项目对象模型,这个过程需要一段时间,这时候Gradle守护进程就是为了解决这个问题。
Gradle守护进程的出现就是以后台的方式运行Gradle,gradle命令就会在后续的构建之中重用之前的进程,避免了启动时造成的开销。
如何开启守护进程?我们在运行gradle命令时,加上--daemon
选项,一旦启动就可以看看系统进程表(Max OS X或者linux就在shell中运行命令 ps | grep gradle ,Windows中直接用任务管理器查看):
通过 gradle mG0 gT --daemon 实践:
这时候查看任务管理器:
守护进程会在3个小时空闲时间自动过期,任何时候你都可以选择构建不适用守护进程,加上–no–daemon即可,如果手动停止进程,可以执行 gradle --stop命令。
下面展示如何在构建apk中,在Andorid Manifest.xml添加meta-data,用Gradle脚本自动完成:
(1)第一种方法,在app的build.gradle中编写,提前导入 import groovy.xml.*
然后在Terminal中输入:
接下来就可以在Manifest.xml中看到:
(2)第二种方法
导入两个类 import com.android.build.gradle.api.ApplicationVariant
import groovy.xml.XmlUtil
同样也是可以的。
Gradle的项目构建分为三个阶段:初始化、配置、执行。
在这个阶段中,Gradle决定哪些项目加入到构建中(因为Gradle支持多项目构建),并为这些项目分别创建一个Project
实例。
Gradle支持多项目构建和单项目构建,如果是单项目构建,则初始化当前项目即可,如果是多项目构建,则需要决定哪些项目需要加入到构建中并初始化,那么Gradle是如何判断当前构建的是单项目还是多项目呢?如果是多项目,Gradle又是如何决定将哪些项目加入到构建中呢?
多项目还是单项目构建
这里的关键是一个名为settings.gradle
,Gradle构建初会去寻找这个文件,查找的规则如下:
-
查找当前构建目录下的
settings.gradle
文件。 -
如果没有找到, 则去与当前目录有着相同嵌套级别的
master
目录查找 -
如果没有找到则去父目录中找
-
如果没有找到,则进行单项目构建
-
如果找到了,Gradle就检查这个文件中是否有定义,如果没有定义多项目,则进行单项目构建,否则进行多项目构建。
多项目工程根目录必须存在 settings.gradle文件中,单项目工程可以不需要这个目录。
多项目构建的项目集如何确定?
多项目构建时,项目集由settings.gradle中定义,项目集可以用一个树型结构表示,每个节点表示一个项目,并且有对应的项目路径。
下面就是一个多项目的settings.gradle文件:
include ‘project1’, ‘project2:child’, ‘project3:child1’
include
方法接收多个项目路径作为参数。
每个项目路径对应文件系统中的一个目录,通常情况下项目路径和文件目录一一对应,比如project2:child就是对应project2/child目录。
如果项目树的叶节点和它的父节点都需要包含在构建中,则只需指定子节点即可。
比如project2:child,将创建两个项目实例 project2和project2:child
扁平化布局:
includeFlat ‘project3’, ‘project4’
includeFlat方法将目录作为参数,这些目录是根项目目录的兄弟项目,并作为多项目中根项目的子项目。
Settings语法
这里主要说一下include
方法的语法,其余的语法请对应:传送门
settings.gradle在构建时会创建代理对象
Settings
,其include方法对应着Settings.include(java.lang.String[])
。
-
include方法接收项目路径数组作为参数,并将对应的项目添加到构建中
-
参数中支持的项目路径分隔符为“:”而不是“/”
-
路径中最后一个节点是项目名称
-
项目路径是根项目 目录下的相对路径
可以使用ProjectDescription.setProjectDir(java.io.File)更改
示例:
// 引入两个项目, ‘foo’ and ‘foo:bar’
// 对应的文件目录是 $rootDir/a 和 $rootDir/a/b
// directories are inferred by replacing ‘:’ with ‘/’
include ‘foo:bar’
// include one project whose project dir does not match the logical project path
// 引入‘baz’项目,对应的文件目录是foo/baz
include ‘baz’
project(‘:baz’).projectDir = file(‘foo/baz’)
默认情况下,Gradle会配置settings.gradle里的所有项目,不论这些项目与最终执行的任务是否有关。
项目配置按照广度配置(breath-wise)顺序配置,如父项目先于子项目配置。
按需配置模式
一个多项目构建中,可能存在大量无需配置的项目,如果需要配置所有的项目后才能运行程序, 则会浪费大量的时间,在Gradle1.4开始引入了按需配置模式。
在这个模式下,Gradle只配置与最终任务相关联的项目,以缩短构建时间,这个模式以后会成为默认模式。
按需配置模式下,项目配置遵循如下规则:
-
根项目总会被配置
-
构建的当前项目也会被配置
-
项目的依赖会被配置
-
任务依赖的对应项目会被配置(就是之前讲过的dependsOn)
-
通过命令行构建任务时会配置相应的项目。比如构建 'project A:project B:someTask’时会配置projectB
进行构建时,可以在命令行加入gradle xxxx --config-on-deamon
来指定按需配置模式来进行构建。
在这个阶段之前,Gradle已经决定好了要构建的项目集,项目集由输入到命令行和当前目录决定的,然后Gradle会去执行任务集中的每个任务。
任务(Task)是由一系列活动(action)构成,当任务执行的时候,活动会依次执行。可以通过doFirst和doLast方法将活动添加到任务中。
那么在多项目构建时,Gradle是如何确定任务是哪个项目的?尤其是任务名称相同的情况下?
其次是Gradle如何确定多任务的执行顺序?
任务的位置
以命令行**$ gradle hello**为例,在执行阶段,Gradle会从构建的当前项目目录开始,依据项目树,往下查找名为 hello 的Task并执行,因此Gradle不会执行当前项目的父项目和兄弟项目的任务。
任务的顺序
如果没有额外的配置,Gradle将会以字母数字的顺序执行任务,比如“:consumer:action”将先于“:producer:action”执行
创建项目目录
$ mkdir single-project-build-lifecycle-demo
$ cd single-project-build-lifecycle-demo
创建settings.gradle文件
$ vi settings.gradle
在settings.gradle中:
rootProject.name = ‘single-project-build-lifecycle-demo’
println ‘settings.gradle -> this is executed during the initialization phase.’
创建build.gradle
创建build.gradle文件
$ vi build.gradle
println ‘build.gradle -> global println -> This is executed during the configuration phase.’
最后
文末放一个小福利给大家,点击我的GitHub即可领取
群内有许多技术大牛,有任何问题,欢迎广大网友一起来交流,群内还不定期免费分享高阶Android学习视频资料和面试资料包~
偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-L3GYf8qm-1711006894356)]
[外链图片转存中…(img-oTBFaxVh-1711006894357)]
[外链图片转存中…(img-0fkRDMSt-1711006894357)]
[外链图片转存中…(img-GCA2BbOD-1711006894358)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-lREfRvLa-1711006894358)]