Groovy语法Gradle配置学习笔记

news/2024/5/20 3:05:53 标签: Groovy, Gradle

Groovy_0">第一部分: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.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 和 for 语法

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.'
    }
}

在这里插入图片描述

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 name
    int age
}

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

xml 解析

import groovy.xml.MarkupBuilder

final 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].@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格式数据
* <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 = 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
}

groovy 与 java 对比

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

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

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

Gradle_755">第二部分:Gradle配置

Gradle_757">认识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() {
    // 获取当前工程的所有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'
}

文件相关的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.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 // 每次都从服务端拉取
}

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是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}"
    }
}

Task 的执行顺序

在这里插入图片描述

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>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.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<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() - 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'引入。

Gradle__1429">将自定义任务挂接到 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.checkManifest
        checkTask.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.niftyadmin.cn/n/5093111.html

相关文章

WAF绕过-漏洞发现之代理池指纹探针 47

工具 工具分为综合性的&#xff0c;有awvs&#xff0c;xray&#xff0c;单点的比如wpscan专门扫描wordpress的。而我们使用工具就可能会触发waf&#xff0c; 触发点 第一个就是扫描速度&#xff0c;太快了&#xff0c;可以通过演示&#xff0c;开代理池&#xff0c;白名单绕…

【C++STL基础入门】stack栈的增删查等操作的使用

文章目录 前言一、stack元素访问1.1 元素访问之top 二、stack修改2.1 stack修改之push()函数2.2 stack修改之pop()函数2.3 stack修改之swap()交换函数2.4 stack修改之emplace()在顶部原位构造元素 总结 前言 在C的标准模板库(STL)中&#xff0c;stack&#xff08;栈&#xff0…

Mybatis-Plus3.x的使用

MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为 简化开发、提高效率而生。 一、引入 创建步骤&#xff1a; 1.创建Spring Boot工程 2.添加依赖 引入 Spring Boot Starter 父工程&am…

React高级特性之受控和非受控组件

一、受控组件 受控组件&#xff1a;input框自己的状态被React组件状态控制 // 类组件引入React import React from reactclass InputComponent extends React.Component{state {message: zm66666}changeHandler (e) > {this.setState({message: e.target.value})}render…

第五十八章 学习常用技能 - 查看查询缓存

文章目录 第五十八章 学习常用技能 - 查看查询缓存查看查询缓存建立索引使用调谐表工具 第五十八章 学习常用技能 - 查看查询缓存 查看查询缓存 对于 SQL&#xff08;用作嵌入式 SQL 时除外&#xff09;&#xff0c;系统会生成可重用代码来访问数据&#xff0c;并将该代码放置…

04-React脚手架

04-React脚手架 1. react脚手架入门 1).脚手架的介绍 xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目 包含了所有需要的配置&#xff08;语法检查、jsx编译、devServer…&#xff09;下载好了所有相关的依赖可以直接运行一个简单效果 react提供了一个用于创建rea…

GEE案例——计算指定区域的云量所占的面积占比(以2019年-2022年北京市为例)

简介: 这里我们使用哨兵2号数据,将北京市所在区域2019年-2022年之间的区域计算每张影像的云量计算和像素的数量,从而给出每张影像云量所占的百分比,并可以查看指定时间范围内的单张影像去云后的影像,这里会在地图中加载一个下拉框选取指定应影像。 解译非常重要。云量是…

系统对接-验签机制

一、消息摘要算法 1、消息摘要算法特点 消息摘要算法加密过程不需要密钥&#xff0c;加密的数据无法解密。 只有输入相同的明文并且使用相同的摘要算法才能得到相同的结果。 2、MD5算法 压缩性&#xff1a;任意长度的数据MD5值都是固定128位&#xff08;32个16进制数值串&a…