Gradle3.0自动化项目构建技术和实战
文章目录
一. 课程介绍
1.1 课前必读
-
已经会使用Ant、Maven,为什么还要学Gradle?
- 它是一款最新的,功能最强大的构建工具,用它逼格更高。(Maven/Ant 能做的事情,它都可以做,同时它具有一些其他不具有的功能,更强大)
- 使用程序代替传统的XML配置,项目构建更灵活。(Gradle本身是一个程序语言)
- 它含有丰富的第三方插件,让你随心所欲使用。(方便的完成我们的项目需求)
- 完善Android,Java开发技术体系,提升自动化构建技术深度。
- 进阶为高级工程师必备,获得薪资更高的offer。
-
适合人群:
- 所有从事于Android,Java相关的开发人员。
- 有Android,Java基础,对工程构建有一定的了解。
- 和课程目标一样,想升职加薪,拿到称心如意的offer。
1.2 课程导学
-
第一部分内容:Gradle相关介绍及开发环境搭建
- 我们主要讲解Gradle的相关概念
- Windows/Linux/Mac下开发环境搭建及工程创建
-
第二部分内容:Gradle的核心语法讲解及实战
- 字符串的特殊用法
- Gradle常见数据结构(list,map,range)的使用
- Gradle面向对象的特性
-
第三部分内容:Gradle高级用法的实战(非常重要,对后面自动化构建有帮助)
- json文件处理及json,model互转
- xml文件读取和生成
- 普通文件的读写
- 网络请求json并转化为实体对象实现
- 文件下载功能实现
-
第四部分内容:Gradle核心之Project详解及实战
- Project类核心作用
- 核心Api讲解
- Gradle生命周期流程
- 版本统一管理
- Project源码解读
-
第五部分内容: Gradle核心之Task讲解及实战(整个课程中最为核心的内容)
- Task定义和使用,Task执行流程
- Task依赖关系与输入输出,Task继承与实现
- Task修改默认构建流程,Task源码解读
- 综合实战1:自动化生成版本说明xml文档
- 综合实战2:自动化实现工程插件更新功能
-
第六部分内容: Gradle核心之其他模块讲解及实战
- 第三方库依赖管理及Gradle如何去处理依赖原理讲解
- 工程初始化核心类Setting类作用及自定义
- 源码管理类SourceSet讲解及实际工作中的妙用。
- 相关核心类的源码解读。
-
第七部分内容:Gradle核心之自定义plugin实战
- 插件类Plugin的定义和如何使用第三方插件
- Gradle如何管理插件的依赖
- 插件类Plugin源码解读
- 综合实战:将前面的自动化脚本封装为插件供他人使用。
-
第八部分内容:Gradle程序修改默认打包流程
- Android,Java工程打包流程讲解
- 将脚本嵌入到Gradle打包流程中实现我们的特定功能
- 打包流程核心task图解
- 综合实战:将前面编写的脚本嵌入到打包流程中。
二. Gradle快速入门
2.1 本章概述
- Groovy概述
- 领域特定语言DSL介绍
- groovy讲解之groovy初探
- 为什么选择Grovvy及优势
2.2 什么是领域特定语言DSL?
- DSL,全称domain specific language(只用于做计算的语言),Groovy是其一个分支,用于做脚本,与Python,Ruby类似。
- 概念: DSL 是在需求分析阶段中为了解决需求收集过程中需求描述方(遇到问题方/问题描述者[注意:遇到问题方通常是客户或者用户,而描述方通常是出现该问题的所在行业的专家,这两个角色可能是同一个人,也可能是不同的人])与解决方案提供方(构建者)间互相理解困难而设计的专门工具。在需求收集中,首先需要理解问题方遇到的问题,然后将其映射到解决方案提供方的解决技术上。用术语描述的话,问题描述者(描述领域活动的背景和问题)称为“领域专家”,其使用“行话”来说明;解决方案提供者称为“模型构建者”,其通过对领域活动及其问题的理解,加上对技术解决方案的理解,提出解决方案模型。该模型最终映射到技术方案中。这个过程中的活动成为“领域分析/领域建模”。其目的是确定并理解领域中的重要元素、过程以及其间的关系。
- 常见的 DSL
- 软件构建领域 Ant
- UI 设计师 HTML
- 硬件设计师 VHDL
- DSL 的特点:
- 用于专门领域,不能用于其他领域
- 表现力有限
- 不描述解答域,仅描述问题域
- DSL 与通用编程语言的区别
- DSL 供非程序员使用,供领域专家使用
- DSL 有更高级的抽象,不涉及类似数据结构的细节
- DSL 表现力有限,其只能描述该领域的模型,而通用编程语言能够描述任意的模型
通俗来讲,DSL与编程语言的区别在于,DSL着力于更深入的解决某一个问题。而编程语言则为通用性,普适性而努力。
- 如何构建DSL:
- 能够完整描述领域
- 简单易用
- 隐藏实现细节
- 何时使用DSL?
- DSL 的构建难度比较大,从零构建不合适。建议使用比较完善的构建。
- 总结一句话: 求专不求全,解救特定问题。
2.3 groovy初探
- 概述:
- 是一种基于JVM的敏捷开发语言
- 结合了Python、Ruby和Smalltalk的许多强大的特性,且它与Java语言类似,上手快。
- groovy可以与Java完美结合,而且可以使用java所有的库(Python/Ruby等不能使用java的库)
- groovy特性:
- 语法上支持动态类型,闭包等新一代语言特性
- 无缝集成所有已经存在的Java类库
- 即支持面向对象编程也支持面向过程编程
- groovy优势
- 一种更加敏捷的编程语言
- 入门非常的容易,但功能非常的强大(在已经会java的情况下,学习很快)
- 即可以作为编程语言也可以作为脚本语言
- 熟练掌握Java的同学会非常容易掌握Groovy
- 必知必会:
- 对领域特定语言DSL有一定认识。
- 对Groovy的基本概念有一定的认识。
- 了解Groovy有哪些自己的特点和优势。
三. 开发环境搭建
3.1 本章概述
- mac/linux环境下,groovy开发环境搭建
- windows环境下,groovy开发环境搭建
- Intellij IDEA开发工具安装及groovy环境配置
- 在IDEA中创建一个groovy工程
- 需要同学们提前安装好JDK环境(Java的环境)
3.2 linux下环境搭建
- 安装好JDK环境
- 到官网下载好groovySDK,解压到合适的位置,官网,如图所示:
- 在电脑中配置groovy环境变量
- 进入到groovy目录
- 获取路径:
pwd
- 编辑环境变量,使用vim进行编辑,如图所示:
vim ~/.bash_profile
- 重新加载环境变量:
source ~/.bash_profile
- 验证版本:
groovy -version
- 如果出现如图界面,说明安装groovy成功:
3.3 windows下环境搭建
- 下载groovySDK开发工具
下载windows版本
- 打开classpath环境变量设置界面:
我的电脑-> 高级设置-> 环境变量
- 对classpath环境变量进行设置,大致如图:
groovy的地址和版本号根据实际来,所以此处的地址进行相应的变换即可。类似java的环境变量配置。
- 打开cmd窗口,在控制台中输入groovy -version ,校验是否正确安装,出现如图所示版本信息,说明安装成功:
3.5 IntelliJ IDEA中配置groovy
- 到IntelliJ官网下载安装包
- 下载完成后后开始安装
- 在IDEA中配置groovy工程环境(新的IDEA直接用即可,无需安装)
可以先看一下是否安装了groovy插件,如果没有安装,则进行安装后重新加载IDEA即可。
3.6 groovy工程创建
-
如图所示选择好groovy,然后输入工程名称,点击Finish即可创建成功:
-
创建项目成功如图:
-
在groovy项目中,我们可以直接创建java项目,同时我们也可以选择groovy class进行创建,如图所示:
-
我们创建类时可以选择多种groovy类型,其中除了Trait是Groovy独有的类型,其他类型与java类似,如图所示:
-
我们选择 Class 类型,然后创建一个名为 HelloGroovy 的类,然后写一段 Hello,World 的代码,如图所示:
-
既然我们可以用java语法去写groovy,同时我们也可以以groovy的风格去写groovy,改造Hello,world后的代码如图所示:
-
从上面看类似没有多大的变化,我们还可以更简单一点,直接写脚本,不需要写方法即可执行:
从编译器来说,groovy也会自己内部给他建类,建方法,将内容包容进去。所以我们既可以以脚本的形式去写代码,也可以以java的面向对象的形式去写代码;
3.7 本章小结
- 能够完成任意环境下的groovy开发环境的搭建
- 顺利完成IDEA开发工具的安装和配置
- 学会在IDEA中创建一个groovy工程
四. Gradle核心语法讲解及实战
4.1 本章概述
- 要学习的内容
- groovy基础语法
- groovy闭包讲解
- groovy数据结构
- groovy面向对象
- 要求:
- 能够独立配置groovy环境
- 能够创建groovy项目
4.2 基础语法讲解
- groovy变量详解
- groovy变量类型无论是什么类型,最后都是对象类型,我们可以从如图的代码看出,虽然
从图中可以看出,基本类型被打印类的类型时,会变成对象类型。创建groovy的方式是如图:
通过右键点击运行即可运行groovy脚本:
- 在groovy中我们定义变量的时候,既可以指定变量类型如上图所示,同时也可以使用def关键字定义变量,系统会自动根据值的类型为这个变零定义类型,如图所示:
虽然都是一样的def 关键字,但是系统根据11得出x_1是Integer类型,得出变量名为y_1,值为3.1415的数据类型为BigDecimal;
- 什么时候用指定的调用类型,什么时候使用def?
- 使用def的情况: 当此变量仅为自己的系统使用,没有其他调用的时候,建议使用def弱类型。
- 使用指定的调用类型的情况:当此接口或者方法被外界其他地方所调用时,建议使用明确的指定的调用类型,这样可以让对方能够明确的知道需要传什么类型的参数,减少疑惑。
4.3 String讲解
- 在groovy中我们可以使用java的String 类型字符串,同时也可以使用groovy提供的GString,它的使用方式有七八种,我们讲一下最常用的三种定义方式,具体要讲的内容图示如图:
- 定义方式:
- 使用单引号进行定义String
- 代码如图:
def name = 'a ssingle string' println name.class
- 如果有特殊的字符,我们可以使用转义符号转义然后进行展示:
- 代码如图:
- 通过三个单引号定义groovy符号:
- 代码如图:
def thupleName= '''three single string ''' println thupleName
- 使用三引号定义它是有格式的,当我们换行输入的时候,打印时也会进行换行打印:
- 如果需要内容全部放在下面,可以添加一个反斜杠 ** ,即可,如图所示:
有格式的地方建议大家使用这种方式
- 代码如图:
- 使用双引号的形式定义格式:
-
代码如下所示:
def doubleName= "this a common String " println doubleName.class
-
如果使用可扩展的表达式(能够执行逻辑计算、放置变量等操作),则类型会从String变为GStringImpl,如图所示:
GStringImpl是最常用的,它的 ${} 内部可以进行计算,可以放置任意的表达式;
-
GString与String 是可以互通的,一个方法接收String类型的参数,它就可以接收GString类型的数据,我们可以不必在乎它究竟是哪个类型的,因为之间是能够互相转换的,就跟java的基本类型和包装类型一样。
-
- 使用单引号进行定义String
4.4 字符串方法讲解
- String中含有的方法有很多,通过以下图示,我们将String 中的方法分为以下几类。
StringGroovyMethods类型的方法是最为常用,重要的方法,需要重点记忆。
- String的一些方法示例:
-
center填充方法:
- 解释: 它是以已有的字符,进行两边填充。
- 代码示例:
def str= "groovy" println str.center(8,'a')
实战代码及打印结果如图:
-
padLeft填充方法:
- 将指定的字符串填充至已有的字符串右边,填充的数量+已有的字符数量等于指定数量;指定数量为参数1的位置,指定的填充内容为参数2位置:
- 代码图示:
还有其他的填充方法,比如padRight等,作用类似,填充方向不同而已,不再一一赘述。
-
比较方法,我们比较字符串大小既可以用 compareTo()进行比较,在Groovy中也可以用 > < = 等用来比较基本数据类型的方式比较字符串,比较逻辑如果是为字母则为谁排前面谁大:
-
获取索引方法:我们既可以用 str.getAt(0) 来获取0索引处的字符,也可以通过 str[0]的方式来获取索引。同时我们也可以传一个范围,它会拿到这个范围的字符串,比如: str[0…1]
-
minus减法运算:使用minus减法运算,可以将 被减数中的指定减数字符去掉,如图所示:
-
reverse 倒序重组:将指定的字符串翻转排序,最后的排第一位,第一位排最后一位;
- 代码示例:
def str = "groovy Hello" println str.reverse()
这里进行反转,打印后的结果为: olleH yvoorg
- 代码示例:
-
capitalize()首字母大写
- 代码示例:
def str= "groovy Hello" println str.capitalize()
打印结果为: Groovy Hello
- 代码示例:
-
isNumber()验证是否是数字类型方法
-
toInteger()将字符串转为Integer类型方法
还有类似的方法,比如toLong()等方法
-
4.5 逻辑控制
- 逻辑控制大致有三种逻辑类型,分别有一些小的分支,具体如图所示:
switch/case与java有一些不同,需要重点关注。
- switch/case
- 代码如图所示:
def x=1.23 def result switch(x){ case 'foo': result= 'found foo' break case 'bar': result= 'bar' break case [4,5,6,'inlist']: // 列表 result='list' break case 12..30: // 范围 result='range' break case Integer: // 任意对象 result='integer' break case BigDecimal: result= 'big decimal' break default: result= 'default' } println result
打印结果为 big decimal
如果 集合 [4,5,6,‘inlist’] 里面改为 [1.23,4,5,6,‘inlist’],它将会被匹配到,然后结果打印为 list,并且后续的将不再执行。就是说,匹配集合的话,它会与集合中的内容进行比较。
- 代码如图所示:
- 对范围的循环:
- 对list的循环:
在groovy中list更像是一个数组
- 对Map进行的循环:
对map循环不用先拿到keys或者迭代器,直接可以对对象i进行操作,它就是代表的循环的每一个元素。
4.6 闭包讲解之基础讲解
-
groovy中闭包基础详解
- 图示:
它与方法类似,但是它与方法又有差别。
- 调用方式:
-
无参数
-
有参数
-
多个参数
-
默认参数
任何闭包都有一个隐式的闭包参数。我们指定了参数时,就不存在默认参数了。
-
闭包一定会有返回值:
没有写return 也一定会有返回值的。
-
- 图示:
-
groovy中闭包使用详解
-
groovy中闭包进阶讲解
4.7 闭包使用讲解
-
闭包的用法,如图如下:
-
使用闭包结合,不需要写循环实现阶乘的代码示例:
在调用的方法中调用了闭包,我们需要查看这个闭包使用了几个参数,我们需要对参数进行传参。如果闭包只使用了一个参数,则我们只需要传递一个参数即可。
4.8 字符串与闭包结合使用
- 闭包的用法图示:
- 代码实战:
- each的遍历
String str = 'the 2 and 3 is 5' // each的遍历 str.each{ String temp ->print temp }
each的返回值就是调用者本身。所以打印结果为: the 2 and 3 is 5
- find方法
String str = 'the 2 and 3 is 5' print str.find{ String s -> s.isNumber() }
find 方法的作用是,寻找此字符串中第一个符合结果的值。此 str字符串第一个符合为数字的是2,所以打印结果为: 2
- findAll方法
String str= 'the 2 and 3 is 5' def list = str.findAll{String s -> s.isNumber()} println list.toListString()
findAll方法的作用是,寻找字符串中所有符合结果的值。所以此str字符串调用此闭包的打印结果为: [2,3,5]
- any 方法
String str= 'the 2 and 3 is 5' def result = str.any{ String s -> s.isNumber() } println result
any方法表示判断此字符串内所有字符是否有至少有一个满足闭包条件,返回Boolean,满足返回true,否则false。此中代码表示:判断str字符串内是否有一个字符满足为数字的结果,返回值类型为Boolean.所以打印的结果为 true;
- every 方法
String str= 'the 2 and 3 is 5' println str.every { String s -> s.isNumber()}
every方法表示判断此字符串内所有字符每一个都必须满足闭包条件,满足返回true,否则返回false。 此处打印结果为false
- collect 方法
def list2 = str.collect { it.toUpperCase()} println list2.toListString()
collect方法表示将此字符串中的每个字符作为一个元素,放到一个新的list集合中。简单来讲,就是将此字符串转为list集合。 所以此处转为大写后的集合打印结果为: [T,H,E, ,2, ,A,N,D, ,3, ,I,S, ,5]
- each的遍历
闭包与任何类型的数据结合,都是与方法一起配合的。多看源码,参照源码的定义方式,可以扩展我们的使用思路。
4.9 闭包进阶讲解
-
进阶图示:
-
闭包三个重要的变量,分别为:this,owner,delegate
-
代码演示:
当一个类中只有一个闭包的时候,三个变量的指向都是最近的类。当闭包中嵌套闭包时,this指向这个类,而owner和delegate指向这个闭包,如图所示:
当修改了delegate所引用的对象时,它的指向又会发生变化:
this和owner是不能修改的,而delegate指向可以被修改且可以被指向任意对象。 -
闭包的委托策略
只有做框架的时候做的比较多,了解一下即可,日常使用的不是很多。
4.10 列表学习(上)
-
思维导图:
主要讲解与Java不同的地方
-
定义集合和数组的方式如图:
-
列表的新增和删除
4.11 列表学习(下)
-
list的排序默认排序规则
def sortList= [6,-3,9,2,-7,1,5] sortList.sort() println sortList
使用默认的排序规则,数字类型则按从小到大排序,打印结果为:[-7,-3,1,2,5,6,9]
-
list 的自定义排序方式
def sortList= [6,-3,9,2,-7,1,5] sortList.sort{ a,b ->{a == b ?:0 Math.abs(a)<Math.abs(b)?1:-1}} println sortList
打印结果为: [9,-7,6,5,-3,2,1]
-
list 的英文字母排序
def sortStringList= ['abc','z','Hello','groovy','java'] sortStringList.sort{it-> return it.size()} println sortStringList
此处设置的排序规则为 return it.size() 说明是按照指定的长度进行排序,所以打印的结果为: [z,abc,java,Hello,groovy] . 如果不指定排序规则,默认是以首字母顺序排序。
-
列表的查找:
可以看出,find 和findAll 方法是寻找符合的内容,而any和every是判断是否符合,返回的是Boolean值。
-
列表的最大值和最小值
- list.min()
- list.max()
可以自定义方法,比如先都变成绝对值,再取大小,如图所示:
-
列表的统计
- list.count()
当不设置条件时,统计集合的全部数量。如果设置条件比如统计偶数,代码如图:
4.12 映射讲解(上)
- Map的新建、查询、新增方法如图:
map类型的存入类型可以多种多样,比如可以一个元素为的key为 String类型,value 也为:String ,而另一个元素为String,List,不必保持一致等。
- 修改默认map类型
- 通过as 的方式进行修改:
- 通过显式的定义进行修改:
- 通过as 的方式进行修改:
4.13 映射讲解(下)
-
不带索引和带索引的对象遍历:
-
带key和value的遍历:
-
map的查询: findAll、count、collect、toListString:
利用闭包方法,可以串行完成功能需求。
-
map的分组
-
map的排序
需要注意的是,map的sort排序会返回一个新的map。而list的sort排序是在原有的list进行排序。
4.14 范围讲解
-
思维导图:
-
range的基础使用
-
range的遍历
range本质上也是一个list,对于一些简单的符合的可以优先使用Range. 建议遍历方式优先使用闭包的方式。
它是作为list的一种辅助,对一些特殊的算法作用比较大。
4.15 面向对象讲解(上)
- 主要讲解内容:
- groovy中类,接口等的定义和使用
- groovy中的元编程
- 语法:
- groovy中默认都是public
- 默认继承groovyObject
- 无论是直接 .方法名 还是调用get/set 最终都是调用get/set
- 接口中不允许定义非public 类型的方法
- 代码示例:
- 定义一个类,包含变量和方法:
- 创建对象和调用方法:
- 定义接口
- 定义对象:属性、get、set、构造方法
- 定义一个类,包含变量和方法:
4.16 面向对象学习(下)
-
为类动态的添加一个属性或方法
-
为类动态的添加静态方法
-
属性调用图示:
4.17 本章小结
- 对groovy整体语法特点有一个了解
- 掌握groovy的变量,字符串,数据结构的用法
- 掌握groovy的闭包和面向对象思想
五. Gradle高级用法实战
5.1 本章概述
- groovy json操作详解
- groovy xml文件操作详解
- groovy 与java对比及总结
5.2 json操作详解
- 将实体转为json与将json打印:
- 打印时自动换行,能够便于查看结构:
直接就可以打印带格式的json字符串。在java中需要借助第三方库才能实现。
- 解析json字符串:
- 使用groovy编写网络请求:
5.3 xml文件解析详解
- java处理xml的方式:
- DOM文档驱动处理方式
- SAX事件驱动处理方式:节省内存,但是需要判断开始节点和结束节点。
- 主要内容:
- groovy中如何解析一个xml格式数据
- groovy中如何创建一个xml格式数据
- 解析xml:
-
定义xml文件:
-
解析如下:
-
根据指定的属性名解析:
-
对xml进行遍历:
获取内容中,作者都是李刚的书
-
另外一种遍历方式:
-
小技巧,可以将depthFirst()方法改为 ‘**’ ,效果一样
-
广度遍历:
-
5.4 xml文件生成
-
静态xml文件生成:
-
根据已有的对象数据动态生成xml文件:
- 定义lang对象:
- 定义language对象:
它是根节点下的子节点对象
- 生成:
- 定义lang对象:
-
xml生成流程图:
5.5 groovy文件处理详解
-
java 如何处理文件?
- 节点流,InputStream,OutputStream及其子类
- 处理流,Reader,Writer及其子类
-
所有java对文件的处理类,groovy都可以使用
- groovy扩展了许多更加快捷和强大的方法
-
代码示例:
-
使用__eachLine__遍历文件内容:
-
获取文件内容:
-
使用readLine可以获取每行内容,每一个索引数据代表一行数据:
def result = file.readLines()
-
文件的写入写出:
-
写一个拷贝文件的方法:
def copy(String sourcePath,String destationPath){ try{ // 首先创建目标文件 def desFile = new File (destationPath) if (! desFile.exists()){ desFile.createNewFile() } // 开始copy new File(sourcePath).withReader{ reader-> def lines= reader.readLines() desFile.withWriter{ writer-> lines.each {line -> writer.append(line +"\r\n") } } } } catch (Exception e) { e.printStackTrace() } }
执行拷贝方法代码如图: ,打印结果为 true ,然后在指定目录生成了一个copy的文件. 我们处理它的方法,可以不用关闭流,因为它会自动为我们传入的流关闭。
-
使用对象生成文件的方法:
-
使用 withObjectInputStream 生成方法:
-
5.6 本章小结
- groovy与java 对比
- 写法上:没有java那么多限制
- 功能上:对java已有的功能进行了极大的扩展
- 作用上:既可以编写应用,也可以编写脚本
- 学习总结:
- 对groovy变量,字符串,循环等基本语法的讲解
- groovy中的数据结构:列表,映射,范围用法
- groovy中方法,类等面向对象相关讲解
- groovy中对普通文件,xml,json处理
六. Gradle生命周期探索
6.1 gradle概念及优势
-
概述:
- gradle基本概念讲解
- gradle优势
- gradle执行流程讲解
-
gradle 是什么?能做什么?
- Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML。当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。
通俗地来讲,ant可以自动化打包逻辑,maven也可以,相比于ant,它多做的事是帮你下载jar包。但是maven的打包逻辑太死板,定制起来太麻烦,不如ant好用。gradle就是又能自动下jar包,又能自己写脚本,并且脚本写起来还比ant好用的这么个东西。
-
gradle组成:
使用gradle编程灵活实现自己的功能
-
gradle的优势:
- 灵活性更高
- 扩展性更好
- 兼容性更强:具备ant和maven的所有功能,它是一个编程框架,所以更强大。
- 粒度性更细
6.2 gradle执行流程详解
- 生命周期图:
前两步是为了执行阶段做准备,每个阶段做不同的功能
- 使用监听各个阶段的开始和结束,我们可以在其中使用代码做各种事情
6.3 gradle生命周期监听
- 监听生命周期:
- 在开始阶段进行监听并打印:
- 配置阶段和执行阶段的监听:
- 打印结果如图:
使用 this.gradle.beforeProject{} 以及 gradle.afterProject{}也可以进行监听,达到类似的监听效果;
- 在开始阶段进行监听并打印:
- 为什么执行build执行这么长,且会有其他东西也进行执行?
其他的是build任务的依赖任务,在执行build前会先将其他依赖执行完毕。
6.4 本章小结
- 了解gradle是什么,能做什么
- 明白gradle相较于以前的构建工具优势在哪里
- 掌握gradle的生命周期阶段
七. Gradle核心之Project详解及实战
7.1 project详解
- 概述:
- 深入了解project
- Project核心Api讲解
- Project核心APi实战
- 深入了解Project
- 一个项目它就是一个project,它的每个子项目我们在java中认为是一个模块,在Gradle中认为是一个project。每个project的特征是,它都有一个专属的gradle文件。名字叫做: build.gradle.
7.2 project核心api分解
- Project APi组成:
project非常的重要,它涉及到很多的方面。而task也非常重要,它涉及到我们最常用的一些功能。
7.3 project api讲解
-
获取api:
-
获取指定Project,并操作:
-
配置通用的属性:
allprojects{ group com.xxx version '1.0.0-release' }
-
引入其他的节点工程方式:
subprojects{ Project project -> apply from: '../publishToMaven.gradle' }
它引入了其他的gradle,这样就可以添加一些公关配置,然后通过 apply from 引入了。
从影响范围来讲,allprojects > subprojects > project 。 allproject影响到每个project,subprojects影响到子节点工程,project影响到单个子节点工程。
7.4 属性相关api讲解上
-
为什么build.gradle这个名字是固定的,因为在Project类中默认的名字就叫"build.gradle":
分隔符为 : 号,默认输出位置为build目录。
-
使用变量为数据赋值:
-
使用扩展属性为数据赋值:
-
使用变量和扩展属性,虽然可能感觉比直接赋值更麻烦了一点。但是如果有很多个gradle.build ,就是说有多个项目同时使用了某个依赖或者属性,但是依赖的版本号或者属性值需要保持一致的时候,使用扩展属性或者定义变量,通过allprojects、subprojects引入,能够统一依赖,且减少重复代码和出错可能。
-
使用subprojects引入扩展属性,复用代码
需要用到的地方,则将此subproject引入即可,但是每个引入的project都会生成一个实例,这样不够优雅,我们可以通过根节点写入来解决。
-
在根工程中定义,在任何一个子project中进行调用:
-
最佳实践:
- 定义一个公共版本控制common.gradle:
- 将刚写号的common.gradle引入:
- 直接在每个模块项目中的build.gradle中引用根节点定义的属性变量:
- 定义一个公共版本控制common.gradle:
7.5 属性相关api讲解下
- 定义属性的方式有2种:一种是扩展属性闭包+根节点 一种是接下来要讲的gradle.properties.
- 使用gradle.properties,我们可以存储key=value形式的数据。在gradle.build中可以直接使用定义好的属性。
如果与已有的属性名称重复会发生异常现象。
- 使用gradle.properties实现小功能:
- 定义build.properties:
- 当定义的isLoadTest为true时,才进行加载Test项目:
这串代码写完后,点击右上角的小海豚刷新图标,如果isLoadTest等于false,则Test项目不会被加载。
- 定义build.properties:
7.6 文件属性操作讲解
- 文件操作相关api图示:
- getRootDir().absolutePath: 获取当前根项目下的文件路径
- getBuildDir().absolutePath: 获取build目录下的文件路径
- getProjectDir().absolutePath: 获取当前项目下的文件路径
getRootDir()与getProjectDir().absolutePath值一样。代码如图所示:,有了这几个方法,我们可以利用这些相对路径很方便的创建一些文件。
-
file: 文件定位,自动从当前的project工程中寻找:
-
files: 寻找多个,返回集合
-
文件拷贝:
我们实际工程中,可以将生成的apk文件复制到指定的目录中;
-
使用exclued在拷贝过程中可以过滤指定的文件或文件夹;rename可以对指定的文件或文件夹进行重命名:
-
使用文件树进行遍历和拷贝:
它能将文件夹内的文件映射为树结构并可以进行依次遍历,我们可以结合拷贝等方法,进行相关的一些操作;文件操作Api很多,不一一赘述,需要的时候,直接百度即可。
7.7 依赖相关api讲解及实战
- 使用Buildscript可以配置仓库地址,以及配置插件地址:
- 配置仓库代码:
- 配置我们工程的“插件”地址:
我们在子项目中的build.gradle中可以为应用程序添加第三方依赖;使用exclude可以排除依赖,使用transitive可以设置传递依赖,通常默认为false:
- 占用编译:provided: 在编译时使用,编译完成后不打入生成的jar包中,能够减小打包后的jar包大小。
- 配置仓库代码:
7.8 gradle执行外部命令实战
自己定义的命令,在右侧任务栏gradle中可以直接找到并点击执行。
7.9 本章小结
- project的定义,组织结构以及作用
- 掌握gradle 核心API在实际中的使用
八. Gradle核心之Task详解及实战
8.1 Task内容分类
- Task定义及配置
- Task的执行详解
- Task执行顺序详解及实战
- Task类型
- 挂接到构建生命周期
- Task实战
8.2 Task定义和配置
- 新建Task:
- 直接通过task函数去创建:
- 使用Task容器去创建:
- 直接通过task函数去创建:
- task的配置:
个人推荐使用第一种方式;
8.3 Task执行讲解与实战
- gradle中的生命周期有:配置阶段和执行阶段。而执行阶段只有Task,它占据了一个生命周期。我们可以定义task,在执行阶段就可以执行相关代码;
- 在task中,我们可以使用doFirst函数和doLast函数。一个是在task原生组件之前执行,一个是在其之后执行。
- 使用doFirst和doLast函数写一个小工具:计算build执行时长:
一个build的task任务,是由很多小task集合成的。它执行就会执行一系列的task。
8.4 Task执行顺序详解与实战
8.5 Task依赖详解及实战
- 一个task依赖了其他task,则其他task会先执行。其他task之间如果没有直接依赖关系,则会随机执行。
8.6 Task输入与输出
- 输入类: TaskInputs
- 输出类: TaskOutputs
- 定义一个输入与输出的task脚本:
- 定义task,依赖两个task,一个是读取task,一个是写入task:
依赖使用 dependsOn 关键词。生产者和消费者同时依赖的话,会自动优先执行生产者,此处则写入优先被执行,这样才能读取到结果。
- 定义读取task:
- 定义写入task:
- 定义task,依赖两个task,一个是读取task,一个是写入task:
8.7 挂接自定义Task到构建过程中
- task不仅可以单独执行,还能够挂载到构建过程中。比如我们可以自己定义一个task,在build的最后执行。
- 使用mustRunAfter 关键字,可以将此任务置于指定的其他任务之后:
- 使用doLast配合其他方法,可以将指定的task任务挂载到其他已有的task任务下,此处示例为将writeTask命令挂载到build下,代码如图所示:
- 如果我们将gradle文件放到其他地方,我们一定要在根gradle工程中进行引入:
8.8 Task类型
- Task提供了很多已有的类型,我们可以直接使用,方便一些脚本的编写。可以参考官方文档
- 比如copy(文件拷贝)、zip等任务等,我们还可以对已有的task任务进行自定义和扩展。
8.9 Task学习总结
- Task定义及配置
- Task的执行详解
- Task的依赖和执行顺序
- 挂接到构建生命周期
- 使用Task完成我们自己的构建需求
九. Gradle其他模块讲解与自定义Plugin
9.1 本章概述
- Settings讲解
- SourceSet类讲解及实战
- Plugin讲解及自定义Plugin
- android插件对gradle扩展
- 如何迁移到gradle
- gradle实战总结
9.2 Settings类讲解
- setting占用一个生命周期,gradle的初始化阶段,它决定了哪些类要被处理。
9.3 SourceSet讲解
- Gradle模块图示:
- SourceSet类是对源码资源库的管理,AndroidSourceSet是对于安卓用的,Java的有JavaSourceSet。我们可以修改资源文件路径,如果我们不对其进行赋值,它就会执行自己的默认约定。
- 修改srcDir的路径,代码图示:
- 我们可以将我们的资源分模块存放,传入多个路径就可以将这些路径都变成指定的resource,代码如图:
- 我们不一定必须要放在android的闭包内,写法如图:
9.4 自定义Plugin实战
- 我们可以自定义插件,引入至Gradle中即可,此处略。
9.6 Android及Java插件对Gradle
- 安卓插件:变体
- Java插件: 主要是引入了一些task
9.7 如何迁移到gradle
- 两种方式: 1. 迁移 2.改造
- gradle只会新增三个文件:
它通过这三个文件,会将之前指向其他路径的变成指向Gradle风格的对应路径。所以无论之前的项目结构是什么样的,新工程都能够执行:
9.8 gradle全面总结
- gradle及其生命周期
- project相关概念及方法
- task方法、执行及依赖
- Setting、SourceSet等其他模块类讲解
- android/java插件对gradle的扩展
- 自定义Plugin讲解及实战
十. Gradle持续集成与打包
10.1 持续集成介绍及Jenkins作用
- 本章内容:
- Jenkins介绍
- Jenkins环境搭建
- 使用Jenkins完成打包
- 什么是持续集成?
- 能够自动完成打包及部署,减少相关压力。
- 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
10.2 Jenkins环境变量搭建
-
流程图如图所示:
-
创建环境变量:
-
下载并安装运行:
-
从官网下载jar包
-
执行 jar -jar jenkins.war 包即可执行,可使用后台启动命令运行。
-
使用密码进行登录:
-
打开浏览器并输入密码:
-
选择右侧、自定义安装插件:
-
默认勾选的都保留,除了去掉Ant Plugin,只保留Gradle Plugin构建工具
-
Git可以多选几个,也可以根据自己实际用的什么来:
-
安装完成后进入设置用户名和密码阶段,我们根据自己实际需要设置对应的用户和密码:
-
对全局工具配置:
-
设置JDK:
配置好了点击Apply让其生效;
-
设置JDK与Maven:
JDK路径根据自己实际的来;
-
点击新建创建一个工程:
-
如图所示:
-
输入工程名后如图所示:
-
配置好相关的配置后、点击立即构建即可运行。
-
-
十一. 课程总结
11.1 grovvy学习总结
- DSL/groovy,环境搭建
- grovy核心语法
- groovy高级语法
11.2 gradle学习总结
- gradle生命周期
- gradle核心模块详解
- gradle其他模块讲解
11.3 gradle实战总结
- 一个版本信息维护脚本的开发
- 一个插件下载脚本的总结
- 如何自定义一个插件