Groovy语法Gradle配置学习笔记

第一部分:Groovy语法

变量的类型和定义

在这里插入图片描述

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.classdef str2 = '''\
第一行
第二行
第三行
'''
println str2def name = "Android"
def sayHello = "hello: ${name}"
println sayHelloprintln "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 和 for 语法

switch 语法:

def x = 1.23
def result
// Groovy 中的 switch-case 可以是任何对象
switch (x) {case 'foo':result = 'found foo'breakcase 'bar':result = 'bar'breakcase [1.23, 4, 5, 6, 'inlist']: //列表result = 'list'breakcase 12..30:result = 'range' //范围breakcase Integer:result = 'integer'breakcase BigDecimal:result = 'big decimal'breakdefault: 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 = 11.upto(number) {num -> result *= num } // 通过闭包return result
}
// 通过downto实现求阶乘
def static fab2(int number) {def result = 1number.downto(1) {num -> result *= num } // 通过闭包return result
}println fab(5)
println fab2(5)// 求和1+2+3+...+number
def static cal(int number) {def result = 0number.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 Personprintln "delegate: ${delegate}" // class Person}def say() {def methodClouser = {println "this: "+this // Person@244a4ed8println "owner: ${owner}" // Person@244a4ed8println "delegate: ${delegate}" // Person@244a4ed8}methodClouser.call()// methodClouser.delegate = xxx delegate是可以修改的}
}
Person.classClouser.call()
new Person().say()class Student {String namedef 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 entrydef entrys = students.findAll {student ->return student.value.score >= 60
}
println entrysdef count = students.count { def student ->return student.value.score >= 60 && student.value.sex == 'male'
}
println countdef 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.scoreNumber score2 = student2.value.scorereturn 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 resultstatic def getGrade(Number number) {def resultswitch (number) {case 0..<60:result = '不及格'breakcase 60..<70:result = '及格'breakcase 70..<80:result = '良好'breakcase 80..100:result = '优秀'breakdefault: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 nameInteger agedef 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.'}
}

在这里插入图片描述

Json 解析

//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 nameint age
}

也支持使用三方的如Gson解析库,只要放在libs下面即可。

xml 解析

import groovy.xml.MarkupBuilderfinal String xml = '''<response version-api="2.0"><value><books id="1" classification="android"><book available="20" id="1"><title>疯狂Android讲义</title><author id="1">李刚</author></book><book available="14" id="2"><title>第一行代码</title><author id="2">郭林</author></book><book available="13" id="3"><title>Android开发艺术探索</title><author id="3">任玉刚</author></book><book available="5" id="4"><title>Android源码设计模式</title><author id="4">何红辉</author></book></books><books id="2" classification="web"><book available="10" id="1"><title>Vue从入门到精通</title><author id="4">李刚</author></book></books></value></response>
'''//开始解析此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].@availabledef 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格式数据
* <langs type='current' count='3' mainstream='true'>
<language flavor='static' version='1.5'>Java</language>
<language flavor='dynamic' version='1.6.0'>Groovy</language>
<language flavor='dynamic' version='1.9'>JavaScript</language>
</langs>
*/
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 = 3boolean mainstream = truedef 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 flavorString versionString 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 resdef 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()}//开始copynew 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 nameint 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 = nulltry {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
}

groovy 与 java 对比

  • 写法上:没有 java 那么多的限制

  • 功能上:对 java 已有的功能进行了极大的扩展

  • 作用上:即可以编写应用,也可以编写脚本

第二部分:Gradle配置

认识Gradle工程

在这里插入图片描述
在这里插入图片描述

监听gradle生命周期

/**
* 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是以树形结构来管理工程项目的。

Project相关的API

在这里插入图片描述

根目录build.gradle中添加:

this.getProjects()def getProjects() {// 获取当前工程的所有projectthis.getAllprojects().eachWithIndex{ project, index ->println "getAllprojects-----------project.name: ${project.name} ------------index: ${index}"}// 获取当前工程的所有子projectthis.getSubprojects().eachWithIndex{ project, index ->println "getSubprojects-----------project.name: ${project.name} ------------index: ${index}"}
}

app/build.gradle中添加:

this.getParentProjectName()def getParentProjectName() {// 获取父peojectdef name = this.getParent().nameprintln "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还是libraryproject.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 = 25libAndroidDesign = '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'
}

文件相关的API

在这里插入图片描述

获取根目录:

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.fileinto 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 // 每次都从服务端拉取
}

Task相关的API

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的作用:相同grouptask会被放在一起,在 Android Studio 的右侧gradle面板中可以看到对应的分组

在这里插入图片描述

description的作用:注释说明

task中可以定义的属性:

在这里插入图片描述

注意,task里面直接写println打印的东西会在配置阶段按顺序直接输出,写在doFirstdoLast里面的才会在执行阶段执行

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是preBuildpreBuildTask.doFirst {startBuildTime = System.currentTimeMillis()println "------>the startBuildTime: ${startBuildTime}"}def buildTask = project.tasks.getByName('build') // Gradle最后一个执行的task是buildbuildTask.doLast {endBuildTime = System.currentTimeMillis()println "------>the build cost Time: ${endBuildTime - startBuildTime}"}
}

Task 的执行顺序

在这里插入图片描述

dependsOn定义Task依赖执行顺序

task taskA(group: 'myTasks') {doLast {println "---------------> taskA 执行"}
}
task taskB(group: 'myTasks') {// dependsOn(taskA) // 单独执行taskB也会先执行taskAdoLast {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 destDirrename "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>100</versionCode><versionName>1.0.0</versionName><versionInfo>App的第1个版本,上线了一些最基础核心的功能.</versionInfo></release><release><versionCode>101</versionCode><versionName>1.1.0</versionName><versionInfo>App的第2个版本,上线了一些最基础核心的功能.</versionInfo></release><release><versionCode>102</versionCode><versionName>1.2.0</versionName><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会自动建立依赖关系。

实例:创建一个Task将版本信息写入一个release.xml文件中,并创建一个Task读取其中的信息

import groovy.xml.MarkupBuilder
/**
* 描述:版本发布文档自动维护脚本
* 流程描述: 1、请求本次版本相关信息
*           2、将版本相关信息解析出来
*           3、将解析出的数据生成xml格式数据
*           4、写入到已有的文档数据中
**/
ext {versionName = "1.2.0"// rootProject.ext.android.versionNameversionCode = 102 // rootProject.ext.android.versionCodeversionInfo = 'App的第3个版本,上线了一些最基础核心的功能.' // 实际可通过接口请求获取destFile = file('releases.xml')if (destFile != null && !destFile.exists()) {destFile.createNewFile()}
}
class VersionMsg {String versionCodeString versionNameString 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.destFiledoLast {println "writeTask------------>begin"//将输入的内容写入到输出文件中去def data = inputs.getProperties() // 会返回一个Map<String, Object>对象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() - 1file.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.destFiledoLast {//读取输入文件的内容并显示def file = inputs.files.singleFileprintln "readTask------------>\n"+file.text}
}
// 测试任务,依赖上面两个任务
task taskTestInpusOuts {setGroup('myTasks_handleRelease')dependsOn writeTask, readTaskdoLast {println '输入输出任务结束'}
}

可以将以上任务写到一个单独的gradle文件中,然后在app/build.gradle中通过apply from: 'releaseinfo.gradle'引入。

将自定义任务挂接到 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 就是通过mustRunAfterdependsOn将自定义的Task挂接到系统的构建任务之中的:

在这里插入图片描述

Task 的类型

Gradle提供了很多任务类型,具体可看:

  • https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html
  • https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Delete.html (等等,在左边栏有分类)
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.checkManifestcheckTask.doFirst {println "---------------> checkTask.doFirst"if (variant.buildType.name == 'release') {//update_plugin() // 查看参考packageplugin.gradle 主要是json解析和文件下载}}}
}

修改apk的名称

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{} 闭包中的配置项

android闭包中可以配置的选项可以查看BaseExtension

在这里插入图片描述

通过 sourceSets 修改源文件的默认存放位置:

例如可以修改so文件的默认存放位置、为res文件夹添加分包等

在这里插入图片描述

可以修改哪些内容具体可以查看 AndroidSourceSet 类中哪些可以配置的。

自定义plugin插件

在根目录建立一个名称为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' 
}

在这里插入图片描述

doFirstdoLast方法分别会在被@TaskAction注解的doAction方法的前后执行。

在项目中引入自定义插件后,Android Studio 的 gradle面板中也会显示对应的task任务名称:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/161728.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-input: 把不符合正则校验的值动态清空,只保留符合的值

<el-input v-model"form.profit" placeholder"请输入授权专利新增利润" input"handleInput" clearable />/*** 不符合正则校验,清空*/const handleInput () > {if (form.value.profit) {if (!/^\d*\.?\d*$/.test(form.value.profit))…

基于STM32_DHT11单总线温湿度传感器驱动

基于STM32_DHT11单总线温湿度传感器驱动 文章目录 基于STM32_DHT11单总线温湿度传感器驱动前言一、DHT11&#xff1f;二、原理1.时序1.主机复位信号和 DHT11 响应信号2.信号‘0’的表示3.信号‘1’的表示4.整个数据信号收发流程 2.数据结构 三、驱动1 .h文件&#xff1a;2 .c文…

CSS 笔记/练习

CSS 概述 与 html 配合&#xff0c;实现内容与样式分离样式美化 标签中元素作用 class&#xff1a;class属性用于为元素指定一个或多个样式类。通过为元素添加class属性&#xff0c;可以将其与CSS样式表中的样式规则关联起来&#xff0c;从而改变元素的外观和行为。一个元素可…

网络工程师知识点7

111、IS-IS路由器的三种类型&#xff1f; Level-1路由器&#xff08;只能创建level-1的LSDB&#xff09; Level-2路由器&#xff08;只能创建level-2的LSDB&#xff09; Level-1-2路由器&#xff08;路由器默认的类型&#xff0c;能同时创建level-1和level-2的LSDB&#xff09;…

0基础学习VR全景平台篇第109篇:认识拼接软件PTGui Pro

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01;今天给大家讲解我们全景后期拼接软件PTgui pro&#xff0c;下面我们开始吧&#xff01; &#xff08;PTgui pro软件课程大纲&#xff09; 1.PTGui这个软件是什么 发明人 &#xf…

公司如何防止源代码外泄,保护开发部门代码安全呢?

在智能制造业中&#xff0c;研发人员的开发环境&#xff0c;大多数采用c#开发语言svn 或c#git进行软件系统的开发&#xff0c;但是c#语言如何来防泄密保护呢&#xff1f;德人合科技针对于制造类企业制定了安全稳定的源代码防泄密方案&#xff0c;不影响员工的正常工作&#xff…

【数字图像处理笔记】01-数字图像基础

01-数字图像基础 图像类型 黑白(二值)图像 只有黑白两种颜色的图像称为黑白图像或单色图像&#xff0c;图像的每个像素只能是黑或白&#xff0c;没有中间的过渡&#xff0c;故又称为二值图像。 二值图像的像素值只能为0或1&#xff0c;图像中的每个像素值用1位存储。图像矩阵中…

Eudic欧路词典 for Mac(可离线英语学习工具)

Eudic欧路词典是一款功能强大的英语学习工具&#xff0c;旨在为用户提供全面的词汇解释和例句。该软件整合了多个权威词典&#xff0c;包括牛津、柯林斯等&#xff0c;提供了全面准确的词汇解释和用法示例。同时&#xff0c;它还支持离线使用&#xff0c;用户可以在无网络连接的…

EasyExcel

EasyExcel 官方文档 EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com) 优势 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套SAX模式的API可以一定程度的解决一些内存溢出…

电脑蓝牙与ESP32蓝牙连接,让电脑发现ESP32

win11蓝牙默认只查看常见蓝牙设备。ESP32创建的蓝牙很有可能是看不到的。 再蓝牙设备发现一栏选择高级&#xff0c;才能查看所有蓝牙设备。 只要下面几行代码&#xff0c;就能让PC发现ESP32 #include <BLEDevice.h> // 引入相关库void setup() {BLEDevice::init("…

学习pytorch13 神经网络-搭建小实战Sequential的使用

神经网络-搭建小实战&Sequential的使用 官网模型结构根据模型结构和数据的输入shape&#xff0c;计算用在模型中的超参数coderunning log网络结构可视化 B站小土堆pytorch视频学习 官网 https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html#torch.nn.Se…

图扑智慧仓储数据可视化监控平台

随着市场竞争加剧和市场需求的不断提高&#xff0c;企业亟需更加高效、智能且可靠的仓储物流管理方式&#xff0c;以提升企业的物流效率&#xff0c;减少其输出成本&#xff0c;有效应对市场上的变化和挑战。 图扑软件应用自研 HT for Web 产品搭建的 2D 智慧仓储可视化平台&a…

全流程TOUGH系列软件实践技术应用

查看原文>>>全流程TOUGH系列软件实践技术应用 TOUGH系列软件是由美国劳伦斯伯克利实验室开发的&#xff0c;旨在解决非饱和带中地下水、热运移的通用模拟软件。和传统地下水模拟软件Feflow和Modflow不同&#xff0c;TOUGH系列软件采用模块化设计和有限积分差网格剖分…

JavaScript系列从入门到精通系列第二十篇:使用工厂方法创建JavaScript对象,JavaScript构造函数详解,JavaScript类概念的介绍

文章目录 一&#xff1a;使用工厂方法创建对象 1&#xff1a;原始写法 2&#xff1a;工厂方式 3&#xff1a;结果验证 二&#xff1a;构造函数 1&#xff1a;什么是构造函数 2&#xff1a;构造函数和普通函数的区别 3&#xff1a;构造函数的执行流程 三&#xff1a;类…

计算机网络中的CSMA/CD算法的操作流程(《自顶向下》里的提炼总结)

具有碰撞检测的载波侦听多路访问&#xff08;CSMA/CD算法&#xff09; 以下内容总结&#xff0c;对应《计算机网络自顶向下第七版》第六章链路层和局域网P299 操作流程&#xff1a; NIC&#xff08;适配器&#xff0c;即网络接口&#xff09;从网络层接收数据报&#xff0c;…

pycharm远程连接miniconda完整过程,以及遇到的问题解决

问题1&#xff1a;no-zero exit code(126) env: ‘/home/user2/miniconda3/envs/ihan/bin/python3’: Too many levels of symbolic links Python interpreter process exited with a non-zero exit code 126 因为选择的新建导致太多软连接&#xff0c;先在服务器上建好虚拟环…

【yolov8系列】yolov8的目标检测、实例分割、关节点估计的原理解析

1 YOLO时间线 这里简单列下yolo的发展时间线&#xff0c;对每个版本的提出有个时间概念。 2 yolov8 的简介 工程链接&#xff1a;https://github.com/ultralytics/ultralytics 2.1 yolov8的特点 采用了anchor free方式&#xff0c;去除了先验设置可能不佳带来的影响借鉴Genera…

液压自动化成套设备比例阀放大器

液压电气成套设备的比例阀放大器是一种电子控制设备&#xff0c;用于控制液压动力系统中的液压比例阀1。 比例阀放大器通常采用电子信号进行控制&#xff0c;以控制比例阀的开度和流量&#xff0c;以实现液压系统的可靠控制。比例阀放大器主要由以下组成部分&#xff1a; 驱动…

Ps:变形

Ps菜单&#xff1a;编辑/变换/变形 Edit/Transform/Warp 变形 Warp是自由变换的一种模式&#xff0c;不仅可以用于物体的伸缩扭曲&#xff0c;也可用于人体的局部塑形。 除了从菜单打开&#xff0c;通常情况下&#xff0c;按 Ctrl T 进入自由变换&#xff0c;然后在画面上右击…

专题三:穷举、暴搜、深搜、回溯、剪枝【递归、搜索、回溯】

1、全排列 class Solution { public:vector<vector<int>> ret;vector<int> path;bool check[7];void dfs(vector<int>& nums){if(nums.size() path.size()) {ret.push_back(path);return;}for(int i 0;i < nums.size();i){if(check[i] fals…