最近在学习Gradle,感觉真的很实用的,这里写一下学习笔记吧,以后还可以再来看看。
一、Groovy 语法
先了解一下Groovy语法,新建一个build.gradle文件,然后加上这样一行:task groovy << {}
,然后再添加下面的各种类型操作,执行方式:gradle groovy
即可
1. 定义变量及函数:
a. 型1
def name = "yk3372"
def myFunc = {
println "hello world $name"
}
myFunc()
输出:hello world yk3372
b. 型2
groovy的方法可以当成变量来传递(函数指针?),类似这样:
def myFunc2 = myFunc
myFunc2() // 还可以继续当成函数调用
c. 型3
def doubleIt = {x -> x + x} //闭包
def applyFuncTwice(func, arg) { //高阶函数
func(func(arg))
}
def foo = 5
def fooDoubleTwice = applyFuncTwice(doubleIt, foo)
println "执行两次函数结果:$fooDoubleTwice"
输出:执行两次函数结果:20
2. 列表及遍历
def mylist = ["first", "second", "third"] //列表
def printItem = { item -> println "item: $item" } //闭包函数
mylist.each(printItem) // 遍历,传入上面的方法,执行相应操作
// 还可以简化输出:
mylist.each{println "item: $it"}//结果一样 it可以看成默认遍历的每一项,类似上面item参数
输出:
item: first
item: second
item: third
3. 类定义(跟java类似)
class MyClass {
String name = "yk3372"
def echoMyName() {
println "my id is: $name"
}
}
def classer = new MyClass()
classer.echoMyName()
classer.name = "Jack"//看起来可以直接修改,没有private之类的东西
classer.echoMyName()
输出:
my id is: yk3372
my id is: Jack
4. 闭包设置代理对象
class MyClass {
String name = "yk3372"
def echoMyName() {
println "my id is: $name"
}
}
def classer = new MyClass()
def nameClosure = {
name = "Jack" //没有声明类型
echoMyName() //直接调用函数
}
nameClosure.delegate = classer
nameClosure()
输出:my id is: Jack
发现成功修改了代理类对象的成员变量和调用里面的函数,第一次见 这种语法~~
ps:我觉得可以理解成这样(不确保正确):
def nameClosure(MyClass myclass){
myclass.name = "Jack"
myclass.echoMyName()
}
//猜想,应该是设置完闭包的代理后,相当于里面默认的this变成MyClass的对象了,然后就可以随意更改和调用了~ 让我想到了C++的友元函数?好久没写了不确定,有兴趣可以去查查^_^
二、 Gradle Tasks
task 从名字上看任务,它可以帮我们做一些预定好的操作,比如针对编译android,我们要先编译java文件->class文件,然后打包dex文件,处理res文件….最后生成apk文件。
如果我们手动去做这件事件,会非常累,都是些体力活,重复劳动,因此我们就需要各种各样的task帮我们做这些事情,写一次,以后每次运行一下任务即可。
这样我们就可以方便的得到想要的结果了。
1. 定义Task
a.我们先看这几种:
project.task("task1")
task("task2")
task "task3"
task myTask4
然后我们运行一下gradle tasks
在Other tasks下面输出了(字母表排序):
myTask4
task1
task2
task3
b. 对上面第4种方式进行详细化
task myTask4
myTask4.description = "task 4 desp" // 描述
myTask4.group = "task4 group" // 分组名,默认在other task分组里
myTask4.doLast{println "do the last"} // 执行task时做的事情,每个task最后默认要执行的函数闭包
输出:
Task4 group tasks
-----------------
myTask4 - task 4 desp
Other tasks
-----------
task1
task2
task3
————————————————————————————————
然后我们再执行一下task4,输入
gradle myTask4
输出:
:myTask4
do the last
————————————————————————————————
task myTask4
myTask4.doLast{println "do the last"} //最后执行
myTask4.doFirst{println "do the first"} // 开始执行
myTask4.leftShift{println "left shift > after doLast"} // 最后的后面执行,类似doLast
myTask4 << { // 简单的task
println "hello"
}
task myTask5 << {// 简单的task声明,并传递一个闭包
println "task5"
}
输出:
:myTask4
do the first
do the last
left shift > after doLast
hello
c. task的另一种定义(类似类定义)
task myTask6 {
description "desp"// 等价于: description("desp") 其实是函数调用,不需要等号
group "my group"
doLast {
println "hello"
}
}
结果就不写了,跟上面类似
2. Task之间依赖关系
a. dependsOn:(在android gradle可能是以参数名方式传入,后面会介绍)
比如有两个task,task1 task2,task2的执行要依赖task1的结果,那我们可以这样写:
task task1 {
doLast{
println "task1"
}
}
task task2 {
dependsOn task1
doLast{
println "task2"
}
}
我们执行一下task2:gradle -q task2
-q 是忽略其他信息
输出:
task1
task2
很好,跟我们想的一样
b. finalizedBy:(理解为由xxx来结束的)
比如这种场景:cleanBuild,我们一般先clean,再build,用上面场景也可以,这里我们可以以clean为基准,来实现:
task buildApk {
doLast{
println "build"
}
}
task cleanAndBuild {
finalizedBy buildApk
doLast{
println "clean"
}
}
结果如我们所想先输出clean,后输出build
注:我在写这个的时候发现如果task:buildapk如果放在clean的后面,执行会出错,说找不到property buildApk,解决办法就是这样写:
finalizedBy "buildApk"
然后就可以正确运行了~~感觉像个声明?
c. shouldRunAfter
我的理解是,有任务A、B,两个任务需要都运行,但B的运行需要A运行后执行,然后run A,B,最后执行顺序是:A,B,我们拿AS点击运行,然后就会编译安装APK来模拟下,看看代码来理解:
task RunApk {
doLast{
println "RunApk"
}
}
task installApk {
shouldRunAfter RunApk
doLast{
println "installApk"
}
}
我们执行这个:gradle -q installApk RunApk
不需要区分任务前后
得到结果:
RunApk
installApk
当然,一个事情的做法可以有多种多样,这里只是举个例子来使用这个而已,不一定典型
讲完上面三个后我们再来综合用一下:
现在有buildApk installApk runApk 3个子任务,然后我想写一个总任务叫:installAndRunApk,依赖上面3个子任务写法如下:
task buildApk << {
println "buildApk"
}
task installApk << {
println "installApk"
}
task runApk << {
println "runApk"
}
task installAndRunApk {
dependsOn = ["installApk", "runApk", "buildApk"]
}
输出结果:
buildApk
installApk
runApk
看起来是不是好神奇,顺序竟然对了,我纳闷了好久,发现原来列表是按照字母表排序 >_< 的,好吧,我们来改一下:
task c_buildApk << {
println "c_buildApk"
}
task b_installApk << {
println "b_installApk"
}
task a_runApk << {
println "a_runApk"
}
task installAndRunApk {
dependsOn = ["b_installApk", "a_runApk", "c_buildApk"]
}
哼哼,这次结果就不对了:
a_runApk
b_installApk
c_buildApk
接下来我们来设置一下约束:
task installAndRunApk {
dependsOn = ["b_installApk", "a_runApk", "c_buildApk"]
b_installApk.mustRunAfter c_buildApk
a_runApk.mustRunAfter b_installApk
}
然后再来执行一下gradle -q installAndRunApk
输出:
c_buildApk
b_installApk
a_runApk
dependsOn 除了使用列表外,我们还可以做循环找到匹配的task,写法如下:
task filterApkTask {
dependsOn tasks.matching{ task -> task.name.endWith("Apk")}
doLast {
println "filter task end with Apk"
}
}
3. Task 具体使用(Task types)
上面说了很多task的定义,依赖之类的逻辑处理,那我们该如何应用到项目呢?下面就来说几种使用方式,其他的可以来这里查文档,这里就入门而已
a. Copy
先来看一下下面的task
task copyImages(type: Copy) {
from 'images'
include '*.jpg'
into 'build'
}
// 这个task翻译过来就是这样:把images文件夹里面的jpg文件,复制到build目录下
平时开发时也经常会有这种复制移动需求,这个就可以很好的帮我们做到,只要运行一下这个task就行。具体的Copy参数,我们可以点这里面看一下文档。
我们还可以做个组合任务:
task copyImagesFolders(type: Copy) {
from('images') {
include '*.jpg'
into 'jpeg'
}
from('images') {
include '*.gif'
into 'gif'
}
into 'build'
}
//相当于分类图片,放到不同文件夹,然后把两个文件夹放到build里
除了复制还有删除移动之类的操作,具体可以查阅DSL文档
b. Zip 压缩
task zipImages(type: Zip) {
baseName = 'images'
destinationDir = file('build') //java 文件类型
from 'images'
}
c. 生成Jar包
跟Copy类似,在Gradle里都叫Task Type,作为参数传进去实现对应的功能,类似还有我们可能会常用的Jar包,来看个例子,这个是将lib库生成的class文件,进行打包:
task buildLib(type: Jar) {
from(project.buildDir.toString() + '/intermediates/classes/release')// filepath
destinationDir file(project.buildDir.toString() + '/aa') // file
baseName 'abc' // jar name
manifest {// META-INF/MANIFEST.MF 文件
attributes 'Main-Class': 'MainFrame' // 启动类
attributes 'Class-Path': '.'
attributes 'Manifest-Version': '1.0'
}
}
然后我们运行,就可以在build目录下发现aa目录里有个叫abc.jar
原文地址:http://blog.csdn.net/yk3372/article/details/53045873