Gradle3.0编程与自动化构建
gradle是一款最新的,功能强大的构建工具,它使用程序代替传统的XML配置,构建项目更加灵活。gradle有丰富的第三方插件。
Gradle相关介绍及开发环境搭建
gradle相关概念介绍
-
领域特定语言DSL介绍
-
全称domain specific language:它分三类,包含建模语言,sql,html,groovy等
- 外部DSL
- 内部DSL
- 语言工作台
-
优点
1、提高开发效率,通过DSL来抽象构建模型,抽取公共的代码,减少重复的劳动;
2、和领域专家沟通,领域专家可以通过DSL来构建系统的功能;
3、执行环境的改变,可以弥补宿主语言的局限性。
-
DSL语言与系统编程语言相辅相成,核心思想是求专不求全,解决特定问题
-
-
groovy详解和初探
- 介绍
- groovy是一种基于JVM的敏捷开发语言
- 结合了Python、Ruby和Smalltalk的许多强大特性
- groovy可以与Java完美结合,而且可以使用java所有的库
- 特性
- 语法上支持动态类型,闭包等新一代语言特性
- 无缝集成所有已经存在的java类库
- 即支持面向对象编程也支持面向过程编程
- 介绍
-
groovy优势
- 一种更加敏捷的编程语言
- 入门非常的容易,但是功能非常的强大
- 既可以作为编程语言也可以作为脚本语言
- 有java基础很容易上手groovy
各系统平台下gradle开发环境搭建及工程创建
-
mac/linux环境下,groovy开发环境搭建
- 安装jdk
- 到官网下载groovy,解压到合适位置
- 配置groovy环境变量
- 输入groovy -version测试
-
windows环境下groovy开发环境搭建
- 安装jdk
- 到官网下载groovy,解压到合适位置
- 配置groovy环境变量
- 输入groovy -version测试
-
IntelliJ IDEA开发工具安装及groovy环境配置
- 下载安装idea基础版(无需破解支持groovy)
- 旧版本安装groovy插件
-
在idea中创建一个groovy工程
-
创建项目,选择groovy,指定groovy和jdk目录
-
新建groovy.class,groovy不仅能写java,也能写脚本语言
class HelloGroovy{ static void main(args){ println "hello groovy" } }
-
Gradle核心语法详解及实践
groovy基本类型会自动转为对象类型
字符串特殊用法
- String
- 可以通过def来定义
- GString
- 常用的三种定义方式
- 一般使用单引号:单引号是普通字符串,类似java中的双引号字符串
- 双引号:可扩展字符串,通过变量来拼接–》def sayHello=“hello: ${n}” ,这时它的类型是GStringImpl
- 三引号:预输出字符串,类似html中p标签
- 新增字符串操作
- 字符串扩展可以字符串和任意表达式拼接
- 新增API讲解
- println str.center(8,‘a’’):表示用a填充字符串,原字符串在中间
- println str.padLeft(8,‘a’)向左添加至字符串长度为8位,也有向右添加方法
- 字符串可以直接通过大于小于号进行比较,也可以通过compareTo()函数比较
- 字符串获取其中的:str[0],也可以str.getAt(0),可以获取多个-》str[0…1]
- 字符串减法:str.minus(str2)也可以直接用减号-》str-str2
- 字符串倒序操作:str.reverse()
- str.capitalize():首字母大写
- 判断是否是int类型字符串:str.isNumber()
- 字符串直接转类型:str.toDouble()
- 常用的三种定义方式
gradle常见数据结构包含(list,map,range…)使用
-
逻辑控制
-
顺序逻辑:单步往下执行
-
条件逻辑:if/else,swtch/case
- if/else和其它语言使用基本一样
- switch/case
- 支持任意类型的case(list,range,string,int,double),列表中包含的时候会匹配到
-
循环逻辑:while,for
-
while和其它语言使用基本一样
-
for:可以使用范围0…9特有数据结构
def sum=0 //范围循环 for (i in 0..9){ sum+=i } //循环list,list在这更像一个数组 for (i in [1,2,3,4,56,78,9]){ sum +=i } //map循环 for (i in ['lili':1,'luck':3,'xiaoming':5]){ sum+=i.value }
-
-
-
闭包
-
groovy闭包基础
-
闭包概念
-
闭包定义:闭包可以说是定义在函数中的函数,其实闭包就是一个代码块
//定义闭包 def clouser = {println 'hello groovy'} clouser.call()//简单执行
-
闭包调用:clouser.call(‘will’)/clouser()
-
-
闭包参数
//带参数闭包,这里使用双引号可以取出参数并拼接 def clouser1 = {String name ->println "hello groovy ${name}"}
-
闭包返回值
def clouser = {return "hell ${it}"}//这里it表示输出默认参数,return返回值
-
-
groovy闭包使用-》常用的
-
与基本类型的结合使用
int x=fab(5) println x //结合upto函数,实现阶乘 int fab(int number){ int result=1 1.upto(number,{num->result*=num}) return result } //结合downto函数实现阶乘 int fab2(int number){ int result =1 number.downto(1){ num->result*=num } return result } //闭包累加 int z=numAdd(6) println z int numAdd(int number){ int result =0 number.times { num -> result+= num } return result }
-
与String结合使用
Str ing str ='the 2 and 3 is 5' //字符串遍历,方法后面加闭包 str.each { String temp -> print temp+',' } //find查找符合条件的第一个 println str.find{ String s-> s.isNumber() } //闭包查找所有字符串 def list=str.findAll{String s-> s.isNumber()} println list.toListString() //any方法和闭包判断是否包含数字 def result=str.any { String s-> s.isNumber() } println result str.every//此方法是所有都符合返回ture,否则false //闭包遍历字符串转换大写 def listToUpper=str.collect {it.toUpperCase()}
-
与数据结构结合使用
-
与文件结合使用
-
-
闭包进阶详解
-
闭包的关键变量
def scriptClouser={ println "scriptClouser this:"+this println "scriptClouser owner:"+owner println "scriptClouser delegate:"+delegate } //三个变量输出结果一样 scriptClouser.call()
- this:代表闭包定义处的类
- owner:代表闭包定义处的类或者对象
- delegate:代表任意对象,默认值与owner一致
在类中定义一个闭包,this、owner、delegate三个对象一致;在闭包中定义闭包,this和其它两个就不同;delegate对象被修改后会和owner不同
class Person{ def classClouser={ println "classClouser this:"+this println "classClouser owner:"+owner println "classClouser delegate:"+delegate } } Person p=new Person() p.classClouser.call() //闭包中定义闭包 def nestClouser={ def innerClouser={ println "innerClouser this:"+this println "innerClouser owner:"+owner println "innerClouser delegate:"+delegate } innerClouser.delegate=p//修改默认的delegate innerClouser.call() }
-
闭包委托策略
- 有四种委托策略(OWNER_FIRST,OWNER_ONLY,DELEGATE_FIRST,DELEGATE_ONLY),默认委托策略是OWNER_FIRST
class Person{ String name def pretty ={"My name is ${name}"} String toString() { pretty.call() } def classClouser={ println "classClouser this:"+this println "classClouser owner:"+owner println "classClouser delegate:"+delegate } } class Teacher{ String name } Person p=new Person() p.classClouser.call() def nestClouser={ def innerClouser={ println "innerClouser this:"+this println "innerClouser owner:"+owner println "innerClouser delegate:"+delegate } innerClouser.delegate=p//修改默认的delegate innerClouser.call() } def stu=new Person(name:'xiaoming') def tea=new Teacher(name:'lili') stu.pretty.delegate=tea//修改默认delegate stu.pretty.resolveStrategy=Closure.DELEGATE_FIRST//指定闭包的委托策略 println '输出'+stu.toString()
-
闭包数据结构
-
-
列表
-
列表的定义
def list=[1,2,-3,4,5,6]//定义和初始化,默认是ArrayList def list=[1,2,3,4,5,6] as int[]//int类型数组,也可以和java一样定义 //groovy数组操作和list一样
-
列表的操作
-
增
list.addAll([10,15]) list.add(6)
-
删
assert [1,'2',3,1,1,1].removeAll(['2',3]) assert list.remove(2) assert list.removeAll([4,5]) list.removeAt(1) print list
-
查
//循环list,list在这更像一个数组 for (i in [1,2,3,4,56,78,9]){ print i } //简洁循环 [1,2,3].each{it -> store += it} //find查找符合条件的第一个 println str.find{ String s-> s.isNumber() } //查找所有奇数 def findList=[-3,9,6,2,-7,1,5] def result=findList.findAll{return it%2!=0} print result //any和every方法 findList.any{return it%2!=0} findList.every{return it%2!=0} //查找最大和最小值;也可以闭包指定规则 findList.min() findList.max{return Math.abs(it)}//闭包绝对最大值 findList.count()
-
排
def list=[1,2,-3,4,5,6] Comparator mc={ a,b-> a==b? 0:Math.abs(a)<Math.abs(b)? -1:1 } Collections.sort(list,mc)//根据自定义排序规则,进行绝对值大小排序 println list //groovy更加简洁的排序,可以传入排序规则,可以闭包排序 list.sort() def sortStringlist['abc','z','hello','groovy','java'] sortStringList.sort{it ->return it.size()}//按照字符串长度排序
-
-
-
映射
def colors=[red:'ff0000',green:'00ff00',blue:'0000ff'] //索引方式 println colors['red'] colors.red //添加元素 colors.leftShift(white:"fffff") colors.yellow='ffff00' colors.complex=[a:1,b:2]//可以添加任意元素到map println colors.toMapString() println colors.getClass()//LinkedHashMap默认是LinkedHashMap,可以通过as关键字修改映射类型 //遍历 colors.each { def color-> println "this key is ${color.key},"+ "the value is ${color.value}" } colors.eachWithIndex{ def entry, int i -> println "this key is ${entry.key},"+ "this index is ${i},"+ "the value is ${entry.value}" } colors.each { def key,def value-> println "this key is ${key},"+ "the value is ${value}" } //查找 def entry=colors.find {def c-> return c.value.equals('0000ff') } println entry def students=[ 1:[number:'001',name:'Bob',score:55,sex:'male'], 2:[number:'002',name:'Amey',score:60,sex:'male'], 3:[number:'003',name:'Leo',score:77,sex:'male'], 4:[number:'004',name:'Habby',score:99,sex:'male'] ] //强大的函数直接分组 def group=students.groupBy {def student-> return student.value.score>=60? '及格':'不及格' } println group.toMapString()
-
范围
-
范围的基本概念:范围继承list,但是比list简单点
-
范围操作:
def range=1..10 println range[0] println range.contains(10) println range.from println range.to //遍历 range.each { print it } def result=getGrade(75) println result def getGrade(Number number){ def result switch (number){ case 0..<60: result='不及格' break case 60..<70: result='及格' break case 70..<80: result='良好' break case 80..<100: result='优秀' break } return result }
-
gradle面向对象特性
- groovy中类,接口等的定义和使用
//class Person implements Action{//实现接口
class Person implements DefaultAction{//实现Trait类
String name
Integer age
def increaseAge(Integer years){
this.name+=years
}
@Override
void eat() {
}
@Override
void drink() {
}
@Override
void play() {
}
}
//定义接口
interface Action {
void eat()
void drink()
void play()
}
//定义trait类型,类似接口,但是可以有实现类
trait DefaultAction {
abstract void eat()
void play(){
println 'i can play'
}
}
-
groovy中的元编程
-
groovy在执行方法的时候先判断类中是否有此方法-》有调用,没有-》判断MetaClass中是否有此方法-》判断是否重写了methodMissing()方法-》判断是否重写了InvokeMethod方法-》以上没通过抛出MissingMethodException
//class Person implements Action{ class Person { String name Integer age def increaseAge(Integer years){ this.name+=years } //一个方法找不到时调用它来代替,否则抛出MissingMethodException def invokeMethod(String name,Object args){ return "the method is ${name},the params is ${args}没有此方法" } //一个方法找不到时先调用这个方法然后调用invokeMethod方法 def methodMissing(String name,Object args){ return "this method ${name} is missing" } } def person=new Person(name:"will",age:25) //println person.age println person.cry()//调用一个不存在的方法 //为类动态添加一个属性 Person.metaClass.sex='male' //为类动态添加方法 Person.metaClass.sexUpperCase={-> sex.toUpperCase()} def person2=new Person(name:"will",age:25) println person2.sexUpperCase() //为类动态添加静态方法 Person.metaClass.static.createPerson={ String name,int age->new Person(name:name,age:age) } def person3=Person.createPerson("Amey",30) println person3.name
-
Gradle高级用法实践
gradle中json文件处理及json,model互转,网络json处理
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
def list=[new Person(name:'John',age:25)
,new Person(name: 'mary',age:26)]
def jsonStr= JsonOutput.toJson(list)
println jsonStr
println JsonOutput.prettyPrint(jsonStr)
def jsonSlpuer=new JsonSlurper()
//jsonSlpuer.parse()
println jsonSlpuer.parseText(jsonStr)
//从网络获取json并解析
def response=getNetWorkData('https://www.sojson.com/open/api/lunar/json.shtml')
println response.data.suit//输出网络数据
//获取数据返回对象
def getNetWorkData(String url){
//发送http请求
def connection=new URL(url).openConnection()
connection.setRequestMethod('GET')
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)")
connection.connect()
def responese=connection.content.text
//将json对象转化为实体对象
def jsonSluper=new JsonSlurper()
return jsonSluper.parseText(responese)
}
xml文件读取和生成
import groovy.xml.MarkupBuilder
final String xml='''
<response version-api="2.0">
<current_observation>
<credit>NOAA's National Weather Service</credit>
<credit_URL>http://weather.gov/</credit_URL>
<image>
<url>http://weather.gov/images/xml_logo.gif</url>
<title>NOAA's National Weather Service</title>
<link>http://weather.gov</link>
</image>
<location>New York/John F. Kennedy Intl Airport, NY</location>
<station_id>KJFK</station_id>
<latitude>40.66</latitude>
<longitude>-73.78</longitude>
<observation_time_rfc822>Mon, 11 Feb 2008 06:51:00 -0500 EST
</observation_time_rfc822>
<weather>A Few Clouds</weather>
<temp_f>11</temp_f>
<temp_c>-12</temp_c>
<relative_humidity>36</relative_humidity>
<wind_dir>West</wind_dir>
<wind_degrees>280</wind_degrees>
<wind_mph>18.4</wind_mph>
<wind_gust_mph>29</wind_gust_mph>
<pressure_mb>1023.6</pressure_mb>
<pressure_in>30.23</pressure_in>
<dewpoint_f>-11</dewpoint_f>
<dewpoint_c>-24</dewpoint_c>
<windchill_f>-7</windchill_f>
<windchill_c>-22</windchill_c>
<visibility_mi>10.00</visibility_mi>
<icon_url_base>http://weather.gov/weather/images/fcicons/</icon_url_base>
<icon_url_name>nfew.jpg</icon_url_name>
<disclaimer_url>http://weather.gov/disclaimer.html</disclaimer_url>
<copyright_url>http://weather.gov/disclaimer.html</copyright_url>
</current_observation>
</response>
'''
//开始解析xml数据
def xmlSluper=new XmlSlurper()
def response=xmlSluper.parseText(xml)
println response.current_observation.credit
//自带深度遍历
def taglist=response.depthFirst().findAll {
wind_dir ->
return wind_dir.text
}
println taglist
//children()方法实现广度遍历
//生成xml
def sw=new StringWriter()
def xmlBuilder=new MarkupBuilder(sw)//用来生成xml文件的核心类
//根节点langs创建
xmlBuilder.langs(type:'current',count:'3',mainstream:'true'){
//第一个language节点
language(flavor:'static',version:'1.5',value:'java'){
age('24')
}
language(flavor:'dynamic',version:'1.5',value:'groovy'){
age('16')
}
language(flavor:'dynamic',version:'1.5',value:'javaScript')
}
println sw
//对象生成xml
def langs=new Langs()
xmlBuilder.langs(type:langs.type,count:langs.count,mainstream:langs.mainstream){
langs.languages.each {lang->
languge(flavor:lang.flavor,
version:lang.version,lang.value)
}
}
println sw
class Langs{
String type='current'
int count =3
boolean mainstream=true
def languages=[new Language(flavor: 'static',version: '1.5',value: 'java'),
new Language(flavor: 'static',version: '17',value: '.c++'),
new Language(flavor: 'dynamic',version: '8.0',value: 'javaScript'),
new Language(flavor: 'dynamic',version: '3.5',value: 'python'),
new Language(flavor: 'dynamic',version: '2.4',value: 'groovy'),
]
}
class Language{
String flavor
String version
String value
}
普通文件的读写,文件下载功能实现
def file=new File('../HelloGroovy.iml')
def text=file.getText()//获取文件内容
//def result=file.readLines()
println text
//拷贝文件实现
def result=copyFile("../HelloGroovy.iml",'../HelloGroovy2.text')
println result
def copyFile(String sourcePath,String destationPath){
try{
//创建目标文件
def desFile=new File(destationPath)
if(!desFile.exists()){
desFile.createNewFile()
}
new File(sourcePath).withReader {reader->
def lines=reader.readLines()
desFile.withWriter {writer->
lines.each {line->
writer.append(line+'\r\n')
}
}
}
return true
}catch(Exception e){
e.printStackTrace()
}
}
def person=new Person(name: 'Cherry',age:19)
//saveObject(person,"../person.bean")
def objResult=readObject("../person.bean")
println objResult
//存储类到文件
def saveObject(Object object,String path){
try{
//创建目标文件
def desFile=new File(path)
if(!desFile.exists()){
desFile.createNewFile()
}
desFile.withObjectOutputStream {out->
out.writeObject(object)
}
return true
}catch(Exception e){
e.printStackTrace()
}
return false
}
//在文件中读取类
def readObject(String path){
def obj=null
try{
def file=new File(path)
if(file==null||!file.exists())return null
//从文件中读取对象
file.withObjectInputStream{input->
obj=input.readObject()
}
}catch(Exception e){
}
return obj
}
groovy与java对比
- 写法上:没有java那么多限制
- 功能上:java中的类和方法都可以直接用,对java的功能扩展后,groovy实现功能更方便简洁
- 作用上:既可以编写应用,也可以编写脚本
Gradle概述
gradle是什么,gradle能做什么
-
gradle不仅仅是构建工具,也可以看做是一种编程框架
-
gradle组成部分
- groovy核心语法
- build script block
- gradle api
-
优势
- 更加灵活:Maven和ant不能自己修改构建过程,gradle可以写构建脚本
- 粒度上:gradle开源,构建每一步都清晰可见,可修改
- 扩展性:支持插件,可以复用插件
- 兼容性:gradle吸取了所有构建工具的长处
-
gradle执行分三阶段
-
initialization初始化阶段:解析整个工程中的所有project,构建所有project对应的project对象
-
Configuration配置阶段:解析所有project对象中的task,构建好所有task的拓扑图
-
Execution执行阶段:执行具体的task及其依赖task
/*Android gradle构建阶段监听*/ /*首先在环境变量配置好gradle,具体百度*/ /*在Terminal终端输入-gradlew clean测试*/ /*在project下的build.gradle中添加如下代码*/ /*配置阶段开始前的回调监听*/ this.beforeEvaluate{ println '开始' } /*配置阶段完成以后的回调监听*/ this.afterEvaluate{ println '完成' } /*gradle执行完毕后的回调监听*/ this.gradle.buildFinished{ println '结束' } /*在setting.gradle中输出*/ println '初始化阶段开始' /*执行gradlew clean查看终端输出*/
-
-
Gradle核心类之Project详解及实践
projectAPI组成
-
gradle生命周期api
/*配置阶段开始前的回调监听*/ this.beforeEvaluate{ println '开始' } /*配置阶段完成以后的回调监听*/ this.afterEvaluate{ println '完成' } /*gradle执行完毕后的回调监听*/ this.gradle.buildFinished{ println '结束' } /*project相关api*/ this.getProjects() def getProjects(){ println '--------------------' println 'Root project' println '--------------------' this.getAllprojects().eachWithIndex{Project project,int i-> if(i==0){ println "Root project--- :${project.name}" }else { println "+---*** project: ${project.name}" } } }
-
project相关api
/*project api讲解*/ project('app'){Project project-> // println project.name applay plugin:'com.android.application' dependencies {} android {} } /*配置当前工程和其所有子工程*/ allprojects{ group 'com.will' version '1.0.0=release' } /*配置所有子工程*/ subprojects{ Project project-> if(project.plugin.hasPlugin('com.android.library')){ applay from:'../publishToMaven.gradle'//引入Maven配置文件 } }
-
task相关api
-
属性相关api
/*自定义属性*/ def mCompileSdkVersion =26 def mLibAndroidSupportAppcompatV7 ='com.android.support:appcompat-v7:26.+' /*通用扩展属性,在根build中定义一次,所有子moudle都可以使用*/ ext { compileSdkVersion =26 libAndroidSupportAppcompatV7 ='com.android.support:appcompat-v7:26.+' } /*在moudel中使用*/ android { compileSdkVersion this.rootProject.compileSdkVersion buildToolsVersion "26.0.3" ... } /*因为继承关系也可以直接调用*/ dependencies { compile this.libAndroidSupportAppcompatV7 } /** 我们可以把所有属性通过扩展属性的方式定义到一个新的common.gradle中,在根gradle中通过 apply from:this.file('common.gradle')来引用 */ [外链图片转存失败(img-vvVpPhgt-1568436659006)(https://i.loli.net/2019/03/10/5c846d0725918.png)] //moudle中使用 android{ compileSdkVersion rootProject.ext.android.compileSdkVersion } //在gradle.properties中定义属性 isLoadTest=false isLoadPullRefresh=true mCompileSdkVersion=26 //使用,在setting.gradle include ':app' println '初始化阶段开始' if(hasProperty('isLoadPullRefresh')? isLoadPullRefresh.toBoolean():false){ include ':pullToRefresh' } //在moudel下gradle compileSdkVersion mCompileSdkVersion.toInteger()
-
common.gradle
[外链图片转存失败(img-eIOhgIr3-1568436659008)(https://i.loli.net/2019/03/10/5c846d0725918.png)]
-
-
file相关api
-
路径获取相关api
println "根目录路径"+getRootDir().absolutePath println "build下路径"+getBuildDir().absolutePath println "project的目录"+getProjectDir().absolutePath
-
文件操作相关api
/*gradle拷贝文件,可以拷贝整个目录*/ copy { from file('app.iml') into getRootProject().getBuildDir() //此方法闭包过滤不想拷贝的文件 exclude{} } //文件树遍历 fileTree('build/outputs/apk/'){FileTree fileTree-> fileTree.visit{FileTreeElement element-> println 'the file name is:'+element.file.name copy { from element.file into getRootProject().getBuildDir().path+'/test/' } } }
-
-
其它api
//当有依赖包冲突时可以使用此命令去除冲突的部分 compile this.libAndroidSupportAppcompatV7{ exclude module:'support-v4' //排除指定包下的所有库 exclude group:'com.android.support' transitive false//禁止传递依赖,是否使用引入的库的第三方依赖 } //compile 依赖打包时会把依赖的类和资源打包到apk,provided依赖编译时使用依赖资源,打包时不会打包依赖资源,provided会避免重复引用,尽量使用provided //使用外部命令 task(name:'apkcopy'){ doLast{ //在gradle执行阶段去执行 def sourcePath=this.buildDir.path+'outputs/apk' def desationPath='users/Andministrotor/Download/' def command="mv -f ${sourcePath} ${desationPath}" exec { try{ executable 'bash' args '-c', command println 'the command is execute success' }catch(Exception e){ println 'the command is execute failed' } } } } //buildscript配置maven仓库 buildscript { ScriptHandler scriptHandler-> //配置我们的仓库地址 scriptHandler.repositories { RepositoryIdHelper repositoryIdHelper-> repositoryIdHelper.jcenter() mavenCentral() mavenLocal() //私有的maven仓库配置,可以配置多个 maven { name 'personal' url 'http://localhost:8081:/nexus/repositories' creadentials{ username ='admin' password = 'admin123' } } } //buildscript中的此方法配置我们工程的'插件'依赖地址 dependencies { //此插件指定项目为Android项目 // classpath 'com.android.tools.build:gradle.2.2.2' classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'//引入腾讯热修复框架 } }
Gradle核心之task详解及实践
task定义及使用,task执行流程
使用gradle task命令查看当前项目的task
//创建task,配置组名和描述
task helloTask(group:'will',description:'task study'){
println 'i am helloTask'
doFirst{//可以多次调用,在gradle的执行周期执行,原有的task之前执行
println 'the task group is:'+group
}
doLast{}//原有的task之后执行
}
helloTask.doFirst{//外部调用先执行
println 'the task description is'+description
}
//通过TaskContainer创建task
this.tasks.create(name:'helloTask2'){
//使用set设置组名
setGroup('will')
println 'i am helloTask2'
}
//计算build执行时长的功能
def startBuildTime,endBuildTime
this.afterEvaluate{Project project->
//保证要找的task已经执行完毕
def preBuildTask=project.tasks.getByName('preBuild')
preBuildTask.doFirst {//在此task之前执行
startBuildTime=System.currentTimeMillis()
println 'the startTime is:'+startBuildTime
}
def buildTask=project.tasks.getByName('build')
buildTask.doLast{
endBuildTime=System.currentTimeMillis()
println "the build time is:${endBuildTime-startBuildTime}"
}
}
[外链图片转存失败(img-9FwBZps8-1568436659008)(https://i.loli.net/2019/03/10/5c8498db9288c.png)]
task依赖关系与输入输出,task继承与实现
task taskX {
doLast {
println 'taskX'
}
}
task taskY {
doLast {
println 'taskY'
}
}
task taskZ(dependsOn: [taskX,taskY]) {
dependsOn this .tasks.findAll{ task->
return task.name.startsWith('lib')//动态指定依赖所有lib开头的
}
doLast {
println 'taskZ'
}
}
task lib1 <<{println 'lib1'}
task lib2 <<{println 'lib2'}
//task生成版本说明文件
task handlerReleaseFile {
def srcFile=file('releases.xml')
def destDir=new File(this.buildDir,'generated/release/')
doLast{
println '开始解析对应的xml...'
destDir.mkdir()
def releases=new XmlParser().parse(srcFile)
releases.release.each{ releaseNode->
//解析每个release节点的内容
def name=releaseNode.name.text()
def versionCode=releaseNode.versionCode.text()
def versionInfo=releaseNode.versionInfo.text()
//创建文件并写入节点数据
def destFile=new File(destDir,"release-${name}.text")
destFile.withWriter{ writer->
writer.write("${name} -> ${versionCode} -> ${versionInfo}")
}
}
}
}
task handlerReleaseFileTest(dependsOn:handlerReleaseFile){
def dir =fileTree(this.buildDir.path+'generated/release/')
doLast {
dir.each {
println 'the file name is:'+it
}
println '输出完成...'
}
}
task修改默认构建流程,task源码解读
通过脚本把构建版本信息写入xml,然后在把写入方法添加到构建过程中
//生成版本信息xml和读取,在构建流程中加入添加版本信息到xml
//实际开发中可以把一个独立的gradle功能代码写入单独的gradle文件,然后引入
ext {
versionName = '1.0.0'
versionCode = '100'
versionInfo = 'App的第一个版本,上线了一些最基础的核心功能'
destFile = file('releases.xml')
if (destFile != null && !destFile.exists()) {
destFile.createNewFile()
}
}
task writeTask {
//为task指定输入
inputs.property('versionCode', this.versionCode)
inputs.property('versionName', this.versionName)
inputs.property('versionInfo', this.versionInfo)
//为task指定输出
outputs.file destFile
doLast {
def data = inputs.getProperties()
File file = outputs.getFiles().getSingleFile()
def versionMsg = new VersionMsg(data)
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
if (file.text != null && file.text.size() <= 0) {
xmlBuilder.release {
release {
versionCode(versionMsg.versionCode)
versionName(versionMsg.versionName)
versionInfo(versionMsg.versionInfo)
}
}
file.withWriter {writer->
writer.append(sw.toString())
}
}else{
xmlBuilder.release {
versionCode(versionMsg.versionCode)
versionName(versionMsg.versionName)
versionInfo(versionMsg.versionInfo)
}
//将生成的数据插入到根节点之前
def lines=file.readLines()
def lengths=lines.size()-1
file.withWriter {writer->
lines.eachWithIndex{ String line, int index ->
if(index!=lengths){
writer.append(line+'\r\n')
}else if(index==lengths){
writer.append('\r\r\n'+sw.toString() +'\r\n')
writer.append(lines.get(lengths))
}
}
}
}
}
}
task readTask {
inputs.file this.destFile
doLast {
def file=inputs.files.singleFile
println file.text
}
}
task taskTest {
dependsOn readTask ,writeTask
// shouldRunAfter
// mustRunAfter
doLast {
println '输入输出任务结束'
}
}
class VersionMsg {
String versionCode
String versionName
String versionInfo
}
//在构建流程中加入添加版本信息到xml
this.project.afterEvaluate {project->
def buildTask=project.tasks.getByName("build")
if(buildTask==null){
throw GradleException('the build task is not found')
}
buildTask.doLast {
writeTask.execute()//每次构建项目时把版本信息写入xml文件
}
}
通过查看腾讯tinker源码我们可以知道它把自己的方法插入到gradle构建流程中,在processReleaseManifest之后,在processReleaseResource之前
为了自定义task方便,官方文档提供了很多不同类型的task
[外链图片转存失败(img-wkXRSjPh-1568436659010)(https://i.loli.net/2019/03/10/5c84d143ce2a3.png)]
自动化实现工程插件更新功能
Gradle核心之其它模块详解与实践
第三方库依赖管理及gradle如何处理依赖原理详解
工程初始化核心类Setting类作用及自定义
- settings类在setting.gradle中体现其作用,通过include 引入子工程,并且可以通过自定义属性判断什么条件引入某个工程
源码管理类SourceSet详解及实际工作中的妙用
-
sourceSet类按照约定来管理java中的类和资源,默认从java下获取源码,从res获取资源进行编译;其主要作用就是管理资源、源码、库;Android时通过AndroidSourceSet类管理,java通过javaSourceSet管理
-
sourceSet修改so库即jni默认目录
sourceSets { main { //修改默认so库jni目录到libs下 jniLibs.srcDirs=['libs'] } }
-
SourceSet修改默认的资源文件路径为多路径,对资源进行分类
插件类plugin
自定义plugin需要继承plugin类
-
首先创建一个plugin工程,工程目录结构如下,代码在groovy中,引入配置路径在resources中
//plugin工程gradle文件 apply plugin: 'groovy' sourceSets { main { groovy { srcDir 'src/main/groovy' } resources { srcDir 'src/main/resources' } } } //资源文件下配置引入路径代码 implementation-class=com.will.gradle.study.GradleStudyPlugin //自定义插件groovy类,需要继承plugin类 class GradleStudyPlugin implements Plugin<Project> { /** * 唯一需要实现的就是这个方法,参数就是引入了当前插件的Project对象 * @param project */ @Override void apply(Project project) { println '这里导入了自定义插件' //创建扩展属性 project.extensions.create('imoocReleaseInfo', ReleaseInfoExtension) //创建Task project.tasks.create('imoocReleaseInfoTask', ReleaseInfoTask) } } //自定义ReleaseInfoExtension类,与自定义plugin进行参数传递 class ReleaseInfoExtension { String versionCode String versionName String versionInfo String fileName ReleaseInfoExtension() { } @Override String toString() { """| versionCode = ${versionCode} | versionName = ${versionName} | versionInfo = ${versionInfo} | fileName = ${fileName} """.stripMargin() } } //引入plugin apply plugin: 'com.will.gradle.study' //在app下gradle 中调用plugin定义的方法传递参数 imoocReleaseInfo { versionCode = rootProject.ext.android.versionCode versionName = rootProject.ext.android.versionName versionInfo = '第八个版本。。。' fileName = 'releases.xml' } //在plugin中自定义task,在gradle执行过程中把版本信息写入xml package com.imooc.gradle.study import groovy.xml.MarkupBuilder import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction /** * 自定义Task,实现维护版本信息功能 */ class ReleaseInfoTask extends DefaultTask { ReleaseInfoTask() { group = 'imooc' description = 'update the release info' } /** * TaskAction注解的代码执行于gradle执行阶段的代码 */ @TaskAction void doAction() { updateInfo() } //真正的将Extension类中的信息呢,写入指定文件中 private void updateInfo() { //获取将要写入的信息 String versionCodeMsg = project.extensions. imoocReleaseInfo.versionCode String versionNameMsg = project.extensions. imoocReleaseInfo.versionName String versionInfoMsg = project.extensions. imoocReleaseInfo.versionInfo String fileName = project.extensions. imoocReleaseInfo.fileName def file = project.file(fileName) //将实体对象写入到xml文件中 def sw = new StringWriter() def xmlBuilder = new MarkupBuilder(sw) if (file.text != null && file.text.size() <= 0) { //没有内容 xmlBuilder.releases { release { versionCode(versionCodeMsg) versionName(versionNameMsg) versionInfo(versionInfoMsg) } } //直接写入 file.withWriter { writer -> writer.append(sw.toString()) } } else { //已有其它版本内容 xmlBuilder.release { versionCode(versionCodeMsg) versionName(versionNameMsg) versionInfo(versionInfoMsg) } //插入到最后一行前面 def lines = file.readLines() def lengths = lines.size() - 1 file.withWriter { writer -> lines.eachWithIndex { line, index -> if (index != lengths) { writer.append(line + '\r\n') } else if (index == lengths) { writer.append('\r\r\n' + sw.toString() + '\r\n') writer.append(lines.get(lengths)) } } } } } }
Jenkins持续集成
Jenkins持续集成步骤
- 创建jenkins环境变量
- 下载jenkins.war包
- 执行java -jar jenkins.war,安装jenkins到环境变量指定的位置,期间会有密码输出
- 输入localhost:8080 访问网页进入jenkins,输入密码配置jenkins