Groovy所有类型都是对象类型:
int x = 10
println x.class
double y = 3.14
println y.class
def 定义变量:
def str = "dddd"
println str.class
字符串:
// 单引号 双引号 三引号 字符串模板插入变量 全部支持
def str1 = 'aaaaa\'aa\'aaaa'
println str1
println str1.class
def str2 = '''\
第一行
第二行
第三行
'''
println str2
def name = "Android"
def sayHello = "hello: ${name}"
println sayHello
println "2+3 == ${2+3}"
/* ==================字符串的方法=================== */
// 除了支持java的所有字符串方法外,还支持下面的
def str3 = "groovy"
println str3.center(10, 'a') // 两边以字母a填充,总共长度是10 第二个参数不传是以空格填充
println str3.padLeft(10, 'a')// 左边以字母a填充,总共长度是10
def str4 = 'Hello'
println str3 > str4 // 支持字符串直接比较操作符
println str4[0] // 按下标索引字符
println str4[0..1]
def s1 = "Hello groovy"
println s1 - str3 // 支持直接字符串减法操作符
println str3.reverse() // 反转字符串
println str3.capitalize() // 首字母大写
class Demo{
static void main(args) {
println "hello Groovy"
}
}
switch 语法:
def x = 1.23
def result
// Groovy 中的 switch-case 可以是任何对象
switch (x) {
case 'foo':
result = 'found foo'
break
case 'bar':
result = 'bar'
break
case [1.23, 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 == ${result}"
for 循环:
/**
* 对范围的for循环
*/
def sum = 0
for (i in 0..9) {
sum += i
}
println "sum == ${sum}"
sum = 0
/**
* 对List的循环
*/
for (i in [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
sum += i
}
println "sum == ${sum}"
/**
* 对Map进行循环
*/
for (i in ['lili': 1, 'luck': 2, 'xiaoming': 3]) {
sum += i.value
}
println "sum == ${sum}"
// 闭包定义 闭包一定有返回值,如果不写return, 则返回值为null
def clouser = { String name, int age ->
println "my name is ${name} age is ${age}"
return "result"
}
println clouser("小明", 22)
// 闭包默认参数it
def clouser2 = { it ->
println "my name is ${it}"
}
clouser2("小红")
// 求阶乘
def static fab(int number) {
def result = 1
1.upto(number) {num -> result *= num } // 通过闭包
return result
}
// 通过downto实现求阶乘
def static fab2(int number) {
def result = 1
number.downto(1) {num -> result *= num } // 通过闭包
return result
}
println fab(5)
println fab2(5)
// 求和1+2+3+...+number
def static cal(int number) {
def result = 0
number.times{num -> result += num }
return result
}
println cal(101) // 0加到100
// 字符串与闭包结合使用
String ss = "a b 2 c 2"
ss.each {
print it.multiply(2) // 每个字符变2倍
}
//println ss.find { String s -> s.isNumber() } // find查找符合条件的第一个
def list = ss.findAll { String s -> s.isNumber() } // 返回字符串中所有的数字
println list
println ss.any { String s -> s.isNumber() } // 返回true-字符串中有数字
println ss.every { String s -> s.isNumber() } // 字符串中每一项都是数字才返回true
println ss.collect { it -> it.toUpperCase() }
闭包的三个关键字:this 、owner、delegate
class Person {
def static classClouser = {
println "this: "+this // class Person 指向定义处的类或对象
println "owner: ${owner}" // class Person
println "delegate: ${delegate}" // class Person
}
def say() {
def methodClouser = {
println "this: "+this // Person@244a4ed8
println "owner: ${owner}" // Person@244a4ed8
println "delegate: ${delegate}" // Person@244a4ed8
}
methodClouser.call()
// methodClouser.delegate = xxx delegate是可以修改的
}
}
Person.classClouser.call()
new Person().say()
class Student {
String name
def pretty = {"My name is ${name}"}
String toString() {
pretty.call()
}
}
class Teacher {
String name
}
Student student = new Student()
student.name = "tom"
println student.toString()
列表:
//def list = new ArrayList() //java的定义方式
def list = [1, 2, 3, 4, 5]
println list.class
println list.size()
def array = [1, 2, 3, 4, 5] as int[]
int[] array2 = [1, 2, 3, 4, 5]
/**
* list的添加元素
*/
list.add(6)
list.leftShift(7)
list << 8
println list.toListString()
def plusList = list + 9
println plusList.toListString()
/**
* list的删除操作
*/
//list.remove(7)
list.remove((Object) 7)
//list.removeAt(7)
list.removeElement(6)
list.removeAll { return it % 2 == 0 }
println list - [6, 7]
println list.toListString()
/**
* 列表的排序
*/
def sortList = [6, -3, 9, 2, -7, 1, 5]
Comparator mc = { a, b ->
a == b ? 0 :
Math.abs(a) < Math.abs(b) ? -1 : 1
}
Collections.sort(sortList, mc)
//Groovy的排序方法
sortList.sort { a, b ->
a == b ? 0 : Math.abs(a) < Math.abs(b) ? 1 : -1
}
println sortList
def sortStringList = ['abc', 'z', 'Hello', 'groovy', 'java']
sortStringList.sort { it -> return it.size() } // 按照字符串长度排序 不指定闭包默认按字典序
println sortStringList
/**
* 列表的查找
*/
def findList = [-3, 9, 6, 2, -7, 1, 5]
int result = findList.find { return it % 2 == 0 }
println result
def result2 = findList.findAll { return it % 2 != 0 }
println result2.toListString()
//def result = findList.any { return it % 2 != 0 }
//def result = findList.every { return it % 2 == 0 }
//println result
println findList.min { return Math.abs(it) }
println findList.max { return Math.abs(it) }
def num = findList.count { return it % 2 == 0 }
println num
Map:
//def map = new HashMap()
def colors = [red : 'ff0000',
green: '00ff00',
blue : '0000ff']
//索引方式
println colors['red']
println colors.red
colors.blue
//添加元素
colors.yellow = 'ffff00'
colors.complex = [a: 1, b: 2]
println colors.toMapString()
println colors.getClass() // class java.util.LinkedHashMap
/**
* Map操作详解
*/
def students = [
1: [number: '0001', name: 'Bob',
score : 55, sex: 'male'],
2: [number: '0002', name: 'Johnny',
score : 62, sex: 'female'],
3: [number: '0003', name: 'Claire',
score : 73, sex: 'female'],
4: [number: '0004', name: 'Amy',
score : 66, sex: 'male']
]
//遍历Entry
students.each {student ->
println "the key is ${student.key}, " +
" the value is ${student.value}"
}
//带索引的遍历
students.eachWithIndex {student, index ->
println "index is ${index},the key is ${student.key}, " +
" the value is ${student.value}"
}
//直接遍历key-value
students.eachWithIndex { key, value, index ->
println "the index is ${index},the key is ${key}, " +
" the value is ${value}"
}
//Map的查找
def entry = students.find {student ->
return student.value.score >= 60
}
println entry
def entrys = students.findAll {student ->
return student.value.score >= 60
}
println entrys
def count = students.count { def student ->
return student.value.score >= 60 && student.value.sex == 'male'
}
println count
def names = students.findAll {student ->
return student.value.score >= 60
}.collect {
return it.value.name
}
println names.toListString()
def group = students.groupBy { def student ->
return student.value.score >= 60 ? '及格' : '不及格'
}
println group.toMapString()
/**
* 排序
*/
def sort = students.sort { def student1, def student2 ->
Number score1 = student1.value.score
Number score2 = student2.value.score
return score1 == score2 ? 0 : score1 < score2 ? -1 : 1
}
println sort.toMapString()
range范围:
def range = 1..10
println range[0]
println range.contains(10)
println range.from
println range.to
//遍历
range.each {
print it
}
for (i in range) {
print i
}
def result = getGrade(75)
println result
static 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
default:
result = ''
break
}
return result
}
def person1 = new Person(name: 'Qndroid', age: 26)
println person1.cry() // 注意此方法类中未定义
//为类动态的添加一个属性
Person.metaClass.sex = 'male'
def person = new Person(name: 'Qndroid', age: 26)
println person.sex
person.sex = 'female'
println "the new sex is:" + person.sex
//为类动态的添加方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase() }
def person2 = new Person(name: 'Qndroid', age: 26)
println person2.sexUpperCase()
//为类动态的添加静态方法
Person.metaClass.static.createPerson = {
String name, int age -> new Person(name: name, age: age)
}
def person3 = Person.createPerson('renzhiqiang', 26)
println person3.name + " and " + person3.age
/**
* 1.groovy中默认都是public
*/
class Person implements Serializable {
String name
Integer age
def increaseAge(Integer years) {
this.age += years
}
/**
* 一个方法找不到时,调用它代替
*/
def invokeMethod(String name, Object args) {
return "the method is ${name}, the params is ${args}"
}
/**
* 方法未定义时优先调用methodMissing 如果没有其次找invokeMethod 还没有就报错
*/
def methodMissing(String name, Object args) {
return "the method ${name} is missing"
}
}
/**
* 接口中不许定义非public的方法
*/
interface Action {
void eat()
void drink()
void play()
}
// 允许有默认方法实现的抽象类
trait DefualtAction {
abstract void eat()
void play() {
println ' i can play.'
}
}
//def reponse = getNetworkData('http://yuexibo.top/yxbApp/course_detail.json')
//
//println reponse.data.head.name
//
//def getNetworkData(String url) {
// //发送http请求
// def connection = new URL(url).openConnection()
// connection.setRequestMethod('GET')
// connection.connect()
// def response = connection.content.text
// //将json转化为实体对象
// def jsonSluper = new JsonSlurper()
// return jsonSluper.parseText(response)
//}
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
// 对象序列化成json字符串
def list = [new Person(name:'John', age: 25),
new Person(name:'Jerry', age: 26)]
def json = JsonOutput.toJson(list)
println json
// json字符串反序列化成对象
def jsonSluper = new JsonSlurper()
def list2 = jsonSluper.parseText(json)
println list2[0].name
//jsonSluper.parseText(String text)
//jsonSluper.parse(byte[] bytes)
//jsonSluper.parse(char[] chars)
//jsonSluper.parse(Reader reader)
class Person implements Serializable {
String name
int age
}
也支持使用三方的如Gson解析库,只要放在libs
下面即可。
import groovy.xml.MarkupBuilder
final String xml = '''
疯狂Android讲义
李刚
第一行代码
郭林
Android开发艺术探索
任玉刚
Android源码设计模式
何红辉
Vue从入门到精通
李刚
'''
//开始解析此xml数据
def xmlSluper = new XmlSlurper()
def response = xmlSluper.parseText(xml)
//直接访问解析结果 不需要再转对象
println response.value.books[0].book[0].title.text()
println response.value.books[0].book[0].author.text()
println response.value.books[1].book[0].@available
def list = []
response.value.books.each { books ->
//下面开始对书结点进行遍历
books.book.each { book ->
def author = book.author.text()
if (author == '李刚') {
list.add(book.title.text())
}
}
}
println list.toListString()
//深度遍历xml数据
def titles = response.depthFirst().findAll { book ->
return book.author.text() == '李刚'
}
println titles.toListString()
//广度遍历xml数据
def name = response.value.books.children().findAll { node ->
node.name() == 'book' && node.@id == '2'
}.collect { node ->
return node.title.text()
}
println name
/**
* 生成xml格式数据
*
Java
Groovy
JavaScript
*/
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw) //用来生成xml数据的核心类
// 直接显示的生成一段xml:
根结点langs创建成功
//xmlBuilder.langs(type: 'current', count: '3', mainstream: 'true') {
// //第一个language结点
// language(flavor: 'static', version: '1.5', 'Java')
// language(flavor: 'dynamic', version: '1.6', 'Groovy')
// language(flavor: 'dynamic', version: '1.9', 'JavaScript')
// language(flavor: 'dynamic', version: '1.6') {
// age('10') // 可继续通过闭包形式添加子节点
// }
//}
//println sw
// 根据对象集合动态生成xml
def langs = new Langs()
xmlBuilder.langs(type: langs.type, count: langs.count, mainstream: langs.mainstream) {
//遍历所有的子结点
langs.languages.each { lang ->
language(flavor: lang.flavor, version: lang.version, lang.value)
}
}
println sw
//对应xml中的langs结点
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: 'dynamic', version: '1.3', value: 'Groovy'),
new Language(flavor: 'dynamic', version: '1.6', value: 'JavaScript')
]
}
//对应xml中的languang结点
class Language {
String flavor
String version
String value
}
def file = new File('build.gradle') // 对应项目根目录下
//逐行读取
//file.eachLine { line ->
// println line
//}
//def result = file.readLines()
//一次性读取
def text = file.getText()
println text
//读取文件部分内容
def res = file.withReader { reader ->
char[] buffer = new char[100]
reader.read(buffer)
return buffer
}
println res
def result = copy('build.gradle', 'build222.gradle')
println result
// 使用file的withxxx方法 通过闭包的形式读写文件 不需要关心流的关闭问题 内部做了处理
static 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")
}
}
}
return true
} catch (Exception e) {
e.printStackTrace()
}
return false
}
class Person implements Serializable {
String name
int age
}
def person = new Person(name: 'Qndroid', age: 26)
saveObject(person, "${projectDir}\\person.data")
//todo: 会报错 Person类找不到
def person2 = readObject("${projectDir}\\person.data")
//println "the name is ${person2.name} and the age is ${person2.age}"
static 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 ignored) {
println "saveObject Exception: ${ignored}"
}
return false
}
static 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 ignored) {
println "readObject Exception: ${ignored}"
}
return obj
}
写法上:没有 java 那么多的限制
功能上:对 java 已有的功能进行了极大的扩展
作用上:即可以编写应用,也可以编写脚本
/**
* Gradle生命周期:
* 1.Initialization初始化阶段 解析整个工程中所有的Project, 构建所有的Project对应的project对象
*
* 2.Configuration配置阶段 解析所有的projects中的task, 构建好所有task的拓扑图
*
* 3.Execution执行阶段 执行具体的task及其依赖task
*/
/**
* 配置阶段开始前的监听回调
*/
this.beforeEvaluate {
println "配置阶段开始前--->"
}
/**
* 配置阶段完成以后的监听回调
*/
this.afterEvaluate {
println "配置阶段执行完毕--->"
}
/**
* gradle执行完毕后的监听回调
*/
this.gradle.buildFinished {
println "执行阶段执行完毕--->"
}
this.gradle.beforeProject {}
this.gradle.afterProject {}
Terminal 中执行命令./gradlew projects
可以输出工程中所有的project:
gradle是以树形结构来管理工程项目的。
在根目录的build.gradle
中添加:
this.getProjects()
def getProjects() {
// 获取当前工程的所有project
this.getAllprojects().eachWithIndex{ project, index ->
println "getAllprojects-----------project.name: ${project.name} ------------index: ${index}"
}
// 获取当前工程的所有子project
this.getSubprojects().eachWithIndex{ project, index ->
println "getSubprojects-----------project.name: ${project.name} ------------index: ${index}"
}
}
在app/build.gradle
中添加:
this.getParentProjectName()
def getParentProjectName() {
// 获取父peoject
def name = this.getParent().name
println "getParentProjectName: ${name}"
println "getParentProjectName: ${this.getRootProject().name}"
println "getRootDir: ${this.getRootDir().absolutePath}"
println "getBuildDir: ${this.getBuildDir().absolutePath}"
println "getProjectDir: ${this.getProjectDir().absolutePath}"
}
获取root project:(不管在哪个build.gradle中调都可以)
def getRootPro() {
def name = this.getRootPsoject().name
println "the root project name is: ${name}
}
在根目录的build.gradle
中可以找到具体的某个子project
,并对其进行一些配置:
/** project api讲解 */
project('app') { Project project ->
apply plugin: 'com.android.application'
group 'com.imooc'
version '1.0.Ø-release'
dependencies {
...
}
android {
...
}
}
project('vuandroidadsdk') {
apply plugin 'com.android.library'
group 'com.imooc'
version '1.0.Ø-release'
dependencies {
...
}
}
还可以通过allprojects
这个api对所有的project
进行配置(包括当前节点工程):
allprojects {
// 例如
group "xxx"
version "1.0.2"
}
subprojects
可以对所有子工程的project
进行配置(不包括当前节点工程):
// 不包括当前结点工程,只包括它的subproiect
subprojects {
apply from: '../publishToMaven.gradle'
}
subprojects { Project project ->
println "project.name------------->${project.name}"
// 直接这样调用不能判断,必须写在afterEvaluate中才可以正确判断
// println "project.plugins====${project.plugins.hasPlugin('com.android.library')}"
// 只能通过这种方式判断是application还是library
project.afterEvaluate {
println "is library: " + plugins.hasPlugin('com.android.library')
plugins.withId('com.android.application') {
println("-------------> module application")
}
plugins.withId('com.android.library') {
println("-------------> module library")
}
plugins.withId('java') {
println("-------------> module pure java")
}
}
// project.apply from: '../publishToMaven.gradle' //引入一个写好的脚本
}
可以在根工程中通过ext
定义扩展属性,在子工程中可以直接引用扩展属性:
ext {
compileSdkVersion = 25
libAndroidDesign = 'com.android.support:design:25.0.0'
}
android {
compileSdkVersion this.rootProject.compileSdkVersion
buildToolsVersion "25.0.0
}
dependencies {
compile fileTree(dir: 'libs', include:['*.jar'])
//compile project(':yuandroidadsdk')
compile this.rootProject.libAndroidDesign
}
还可以将版本信息统一定义到一个单独的gradle
文件中,然后在根工程中通过apply
引入该文件:
在子工程中就可以使用上面定义的版本了:
在gradle.properties
中定义变量,然后在settings.gradle
中读取变量值,根据该变量决定是否include
某个子工程:
// gradle.properties
isLoadTest=false
// settings.gradle
include ':app', ':vuandroidadsdk'
include ':lib_pullalive'
if (hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
include ':Test'
}
获取根目录:
println "getRootDir: " + getRootDir().absolutePath
println "getBuildDir: " + getBuildDir().absolutePath
println "getProjectDir: " + getProjectDir().absolutePath
读取文件:
println getContent("settings.gradle")
// 读取文件内容
def getContent(String path) {
try{
def file = file(path) // 相对于当前目录定位文件, 如果使用files()则会返回多个文件
return file.text
}catch(GradleException e){
println e.toString()
}
return null
}
拷贝文件:
//copy {
// from file("settings.gradle")
// into getRootProject().getBuildDir()
//}
copy {
from file("app/build/outputs/apk")
into getRootProject().getBuildDir().path + "/apk/"
// rename {} // 重命名
// exclude {} // 排除不想要/不需要的文件
}
//对文件树进行遍历
fileTree("app/build/outputs/apk/debug") {fileTree ->
fileTree.visit { element ->
println "element.file.name = ${element.file.name}"
copy {
from element.file
into getRootProject().getBuildDir().path + "/test/"
}
}
}
根build.gradle
中的依赖配置:
buildscript { ScriptHandler scriptHandler ->
// 配置我们工程的仓库地址
scriptHandler.repositories { RepositoryHandler repositoryHandler ->
repositoryHandler.jcenter()
repositoryHandler.mavenCentral()
repositoryHandler.mavenLocal()
repositoryHandler.ivy {}
repositoryHandler.maven {
name 'personal'
url 'http://localhost:8081:/nexus/repositories/'
credentials {
username = 'amdin'
password = 'admin123'
}
}
}
}
buildscript {
// 配置我们工程的仓库地址
repositories {...}
// 配置我们工程的"插件"依赖地址
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'
}
}
出现版本冲突时exclude
排除依赖:(子工程build.gradle
中)
compile(rootProject.ext.dependence.libAutoScrollViewPager) {
exclude module:'support-v4' // 排除依赖
transitive false // 禁止传递依赖
}
compile(rootProject.ext.dependence.libTinker) {
changing = true // 每次都从服务端拉取
}
exec
执行外部命令:
task(name: 'apkcopy') {
doLast {
// gradle的执行阶段去执行
def sourcePath = this.buildDir.path + '/outputs/apk'
def desationPath = '/Users/renzhiqiang/Downloads/'
def command = "mv -f ${sourcePath} ${desationPath}"
exec {
try {
executable 'bash'
args '-c', command
prtinln 'the command is execute success.'
}
catch (GradleException e) {
println 'the command is execute failed.'
}
}
}
}
Task的创建:
// 通过task函数创建
task helloTask(group: 'myTasks', description: 'task study') {
println "-----------------------> i am helloTask"
}
// 通过TaskContainer创建Task
this.tasks.create(name: 'helloTask2') {
setGroup('myTasks')
setDescription('task study')
println "-----------------------> i am helloTask2"
}
第一种task的定义实际上是调用了一个task函数:
Task task(String name, Closure configureClosure);
task(helloTask {
println 'i am helloTask.'
})
group
的作用:相同group
的task
会被放在一起,在 Android Studio 的右侧gradle
面板中可以看到对应的分组
description
的作用:注释说明
task中可以定义的属性:
注意,task里面直接写println
打印的东西会在配置阶段按顺序直接输出,写在doFirst
或doLast
里面的才会在执行阶段执行 。
task helloTask(group: 'myTasks', description: 'task study') {
println "-----------------------> i am helloTask"
doFirst {
println "-----------------------> task group is " + group
}
}
helloTask.doFirst { // 这样写执行时机会先于上面那样写
println "-----------------------> task description is " + description
}
使用task计算build执行时间:
def startBuildTime, endBuildTime
// 放在afterEvaluate保证在配置阶段完成以后执行,确保能找到对应的task
this.afterEvaluate { project ->
def preBuildTask = project.tasks.getByName('preBuild') // Gradle第一个执行的task是preBuild
preBuildTask.doFirst {
startBuildTime = System.currentTimeMillis()
println "------>the startBuildTime: ${startBuildTime}"
}
def buildTask = project.tasks.getByName('build') // Gradle最后一个执行的task是build
buildTask.doLast {
endBuildTime = System.currentTimeMillis()
println "------>the build cost Time: ${endBuildTime - startBuildTime}"
}
}
dependsOn
定义Task依赖执行顺序task taskA(group: 'myTasks') {
doLast {
println "---------------> taskA 执行"
}
}
task taskB(group: 'myTasks') {
// dependsOn(taskA) // 单独执行taskB也会先执行taskA
doLast {
println "---------------> taskB 执行"
}
}
// taskC在执行阶段会先执行taskA和taskB
task taskC(group: 'myTasks', dependsOn: [taskA, taskB]) {
doLast {
println "---------------> taskC 执行"
}
}
task helloworld() {
10.times { i ->
tasks.register("task$i") {
doLast {
println "Hello from task
}
}
}
tasks.named("task1") {
dependson "task4", "task6", "task8"
}
dependson "task1"
}
定义一个 copyApk 任务并指定在默认构建任务assembleDebug
之后执行:
task copyApk(type: Copy, dependsOn: "test") {
def sourceDir = layout.buildDirectory.dir("intermediates/apk/debug/app-debug.apk")
def destDir = "$rootDir/apk"
from sourceDir into destDir
rename "app-debug.apk", "gradle-experiment.apk"
doLast {
def file = new File(destDir, "gradle-experiment.apk")
ant.checksum file: file.path
}
}
tasks.whenTaskAdded { task ->
if (task.name == "assembleDebug") {
task.finalizedBy "copyApk"
}
}
查找并依赖以某些名字开头的task任务(如lib库):
task lib1(group: 'myTasks') {
doLast {
println "--------------->lib1"
}
}
task lib2(group: 'myTasks') {
doLast {
println "--------------->lib2"
}
}
// 动态查找依赖task 这里还发现一点需要注意的:依赖的task必须定义在使用的地方前面,否则找不到
task taskApp(group: 'myTasks') {
// 假设taskApp需要依赖所有以lib开头的library module先执行
dependsOn this.tasks.findAll {task ->
return task.name.startsWith("lib")
}
doLast {
println "---------------> taskApp 执行"
}
}
实例:解析一个release.xml
文件并写入到一个独立的文件中
release.xml文件内容:
<releases>
<release>
<versionCode>100versionCode>
<versionName>1.0.0versionName>
<versionInfo>App的第1个版本,上线了一些最基础核心的功能.versionInfo>
release>
<release>
<versionCode>101versionCode>
<versionName>1.1.0versionName>
<versionInfo>App的第2个版本,上线了一些最基础核心的功能.versionInfo>
release>
<release>
<versionCode>102versionCode>
<versionName>1.2.0versionName>
<versionInfo>App的第3个版本,上线了一些最基础核心的功能.versionInfo>
release>
releases>
定义解析Task任务:
// 解析xml文件内容并写入一个独立文件中
task handleReleaseFile {
setGroup('myTasks_handleRelease')
def srcFile = file('releases.xml')
def destDir = new File(this.buildDir, 'generated/release/')
doLast {
println "--------------->开始解析releases.xml文件"
destDir.mkdirs()
def releases = new XmlParser().parse(srcFile)
releases.release.each { releaseNode ->
// 解析每个节点内容
def versionName = releaseNode.versionName.text()
def versionCode = releaseNode.versionCode.text()
def versionInfo = releaseNode.versionInfo.text()
// 创建文件并写入节点数据
def destFile = new File(destDir, "release-${versionName}.txt")
destFile.withWriter{writer ->
writer.write("${versionName}--${versionCode}--${versionInfo}")
}
}
}
}
// 测试任务 依赖上面的任务
task handleReleaseFileTest(dependsOn: 'handleReleaseFile') {
setGroup('myTasks_handleRelease')
def dir = fileTree(this.buildDir.path + '/generated/release/')
doLast {
dir.each{ name -> println "the file name is ${name}" }
println "--------------->输出完成"
}
}
在Terminal中输入执行命令./gradlew handleReleaseFileTest
可以查看结果。
依赖规则:如果上一个Task的输出文件是下一个Task的输入文件,则两个Task会自动建立依赖关系。
实例:创建一个Task将版本信息写入一个release.xml
文件中,并创建一个Task读取其中的信息
import groovy.xml.MarkupBuilder
/**
* 描述:版本发布文档自动维护脚本
* 流程描述: 1、请求本次版本相关信息
* 2、将版本相关信息解析出来
* 3、将解析出的数据生成xml格式数据
* 4、写入到已有的文档数据中
**/
ext {
versionName = "1.2.0"// rootProject.ext.android.versionName
versionCode = 102 // rootProject.ext.android.versionCode
versionInfo = 'App的第3个版本,上线了一些最基础核心的功能.' // 实际可通过接口请求获取
destFile = file('releases.xml')
if (destFile != null && !destFile.exists()) {
destFile.createNewFile()
}
}
class VersionMsg {
String versionCode
String versionName
String versionInfo
}
// 将inputs输入内容写入到outputs中
task writeTask {
setGroup('myTasks_handleRelease')
// 可以设置在每次执行build之后进行写入最新的版本配置信息
// def buildTask = project.tasks.getByName('build')
// dependsOn(buildTask)
// 为task指定输入
inputs.property('versionCode', this.versionCode)
inputs.property('versionName', this.versionName)
inputs.property('versionInfo', this.versionInfo)
// 为task指定输出
outputs.file this.destFile
doLast {
println "writeTask------------>begin"
//将输入的内容写入到输出文件中去
def data = inputs.getProperties() // 会返回一个Map对象
File file = outputs.getFiles().getSingleFile()
//将map转换为实体对象
def versionMsg = new VersionMsg(data)
//将实体对象转换成xml数据写入到文件中
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
if (file.text != null && file.text.size() <= 0) {
//没有内容
xmlBuilder.releases {
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 { line, index ->
if (index != lengths) {
writer.append(line + '\r\n') // 原有的内容直接append
} else if (index == lengths) { // 从最后一行开始拼接新添加的内容
writer.append('\r\n' + sw.toString() + '\r\n')
writer.append(lines.get(lengths))
}
}
}
}
println "writeTask------------>end"
}
}
// 读取inputs文件内容
task readTask {
setGroup('myTasks_handleRelease')
mustRunAfter writeTask
//指定输入文件为上一个task的输出
inputs.file this.destFile
doLast {
//读取输入文件的内容并显示
def file = inputs.files.singleFile
println "readTask------------>\n"+file.text
}
}
// 测试任务,依赖上面两个任务
task taskTestInpusOuts {
setGroup('myTasks_handleRelease')
dependsOn writeTask, readTask
doLast {
println '输入输出任务结束'
}
}
可以将以上任务写到一个单独的gradle
文件中,然后在app/build.gradle
中通过apply from: 'releaseinfo.gradle'
引入。
通过doLast
来指定:
this.project.afterEvaluate { project ->
def buildTask = project.tasks.getByName('build')
if (buildTask == null) {
throw GradleException("the build task is not found")
}
buildTask.doLast{
println "--------------->afterEvaluate"
writeTask.execute()
}
}
通过dependsOn
来指定:
// 设置taskD在build任务之后执行
task taskD(group: 'myTasks') {
def buildTask = project.tasks.getByName('build')
dependsOn(buildTask)
doLast {
println "---------------> taskD 执行"
}
}
通过mustRunAfter
来指定:
task taskB(group: 'myTasks') {
// 如果单独执行taskB不会先执行taskA,只有taskB与taskA一起执行时才有效
mustRunAfter(taskA)
doLast {
println "---------------> taskB 执行"
}
}
// 另外一种写法
taskB.mustRunAfter(taskA)
Tinker 就是通过mustRunAfter
和dependsOn
将自定义的Task挂接到系统的构建任务之中的:
Gradle提供了很多任务类型,具体可看:
task copyDocs(type: Copy) {
from 'src/main/doc'
into 'build/target/doc'
}
task makePretty(type: Delete) {
delete 'uglyFolder', 'uglyFile'
followSymlinks = true
}
this.afterEvaluate {
this.android.applicationVariants.all { variant ->
println "variant.name--------------->${variant.name}"
println "variant.baseName----------->${variant.baseName}"
println "variant.versionCode-------->${variant.versionCode}"
println "variant.versionName-------->${variant.versionName}"
println "variant.flavorName--------->${variant.flavorName}"
println "variant.buildType---------->${variant.buildType.name}"
println "variant.description-------->${variant.description}"
println "variant.assemble----------->${variant.assemble.name}"
println "variant.checkManifest----------->${variant.checkManifest.name}"
def checkTask = variant.checkManifest
checkTask.doFirst {
println "---------------> checkTask.doFirst"
if (variant.buildType.name == 'release') {
//update_plugin() // 查看参考packageplugin.gradle 主要是json解析和文件下载
}
}
}
}
android {
...
productFlavors {
huawei {
dimension "default"
}
xiaomi {
dimension "default"
}
}
task changeApkName() {
applicationVariants.all { variant ->
println "variant.name--------------->${variant.name}"
println "variant.baseName----------->${variant.baseName}"
println "variant.versionCode-------->${variant.versionCode}"
println "variant.versionName-------->${variant.versionName}"
println "variant.flavorName--------->${variant.flavorName}"
println "variant.buildType---------->${variant.buildType.name}"
println "variant.description-------->${variant.description}"
println "variant.assemble----------->${variant.assemble.name}"
println "variant.checkManifest----------->${variant.checkManifest.name}"
//println "variant.signingConfig------>${variant.signingConfig.name}" // null
//def output = variant.outputs.first()
def apkName = "app-${variant.baseName}-${new Date().format('yyyyMMdd')}-${variant.versionName}.apk"
variant.outputs.all { output ->
outputFileName = apkName
}
println "\n"
}
}
}
android
闭包中可以配置的选项可以查看BaseExtension
类
通过 sourceSets
修改源文件的默认存放位置:
例如可以修改so
文件的默认存放位置、为res
文件夹添加分包等
可以修改哪些内容具体可以查看 AndroidSourceSet
类中哪些可以配置的。
在根目录建立一个名称为buildSrc
的工程
然后在其中的groovy
文件夹下面建立groovy类编写代码即可
然后在resources
文件夹下指定该类:
// 位置在 resources/com.imooc.gradle.study.properties
implementation-class=com.imooc.gradle.study.GradleStudyPlugin
在工程中引入应用插件:
apply plugin:'com.imooc.gradle.study'
在自定义的Task
类中的被@TaskAction
注解的doAction
方法中可以读取在build.gradle
中为插件传入的参数信息,然后执行具体的任务(例如将读取的参数信息写入到xml文件中,代码将前面的写入xml内容的部分拷贝过来即可)。如下:
/**
* 为自定义插件传递参数
*/
imoocReleaseInfo {
versionCode = rootProject.ext.android.versionCode
versionName = rootProject.ext.android.versionName
versionInfo = '第8个版本...'
fileName = 'releases.xml'
}
doFirst
和doLast
方法分别会在被@TaskAction
注解的doAction
方法的前后执行。
在项目中引入自定义插件后,Android Studio 的 gradle
面板中也会显示对应的task
任务名称: