Gradle构建详解


1、介绍和环境搭建

DSL(domain specific language):领域特定语言,解决特定问题,包括Groovy,xml等等。

Groovy是一种基于JVM的敏捷开发语言,可以使用java所用的库。

Groovy官网

http://groovy-lang.org/

下载最新稳定版本(the latest stable version of Groovy)-2.5.8版本。

检查环境变量配置

groovy -version

在Android studio中Tools - Groovy Console直接编写Groovy语言。

println "hello groovy"

2、语法

2.1、基础语法

groovy变量的类型都是对象类型,没有基本类型,因为基本类型都会装箱成对象类型。

变量的定义包括强类型定义和弱类型def定义。

def x = 10
println x.class  //class java.lang.Integer

字符串除了String还有GString,GString的常用三种定义方式

def s1 = 'a single \'a\' String'
println s1  //a single 'a' String

def s2 = '''\
line one
line two
line three
'''
println s2  //line one
            //line two
            //line three

def s3 = "a common String"
def say = "this is ${s3}"   //花括号可扩展任意的表达式
println say  //this is a common String
println say.class  //class org.codehaus.groovy.runtime.GStringImpl

新增常用操作符

def str = "groovy"
//println str.center(9,'a')   //agroovyaa
//println str.padLeft(9,'a')  //aaagroovy
//println str.padRight(9,'a')  //groovyaaa

def str2 = 'Hello'
println str > str2  //true

println str[0]  //g
println str[0..1]  //gr

def str3 = 'gro'
println str.minus(str3) //ovy
println str - str3 //ovy

//println str.reverse()   //yvoorg
println str.capitalize()   //Groovy
println str.isNumber()   //false

逻辑控制:

switch

def x = 1.23
def result
switch (x){
    case "str":
        result = 'str'
        break
    case [4,6,7,'inlist']:  //list
        result = 'list'
        break
    case 12..30:    //范围
        result = 'range'
        break
    case Integer:
        result = 'Integer'
        break
    case BigDecimal:
        result = 'BigDecimal'
        break
    default:result = 'default'
}
println result  //BigDecimal

for范围

def sum = 0
for (i in 0..9){
    sum += i
}
println sum //45

list循环

def sum = 0
for (i in [1,2,3,4,5,6,7,8,9]){
    sum += i
}
println sum //45

map循环

def sum = 0
for (i in ['wang':1,'zhang':2,'li':3]){
    sum += i.value
}
println sum //6

2.2、闭包

类似于方法

def clouser = { println "Hello groovy"}
clouser.call()  //调用方式一,Hello groovy
clouser()  //调用方式二,Hello groovy

有参数的闭包->前的是参数,也可以有多个参数

def clouser = {String name -> println "${name} Hello groovy"}
clouser.call("this is")  //调用方式一,this is Hello groovy
clouser("this is")  //调用方式二,this is Hello groovy

隐式的it参数,不需要定义参数

def clouser = {println "Hello ${it}"}
clouser("groovy")  //Hello groovy

返回值

def clouser = {String name -> return  "Hello ${name}"}
println clouser("groovy")  //Hello groovy

基本类型和闭包结合使用

int x = cal(5)
println x   
//num的阶乘
int fab(int number) {
    int result = 1
    1.upto(number, { num -> result *= num })
    return result
}

int fab2(int number) {
    int result = 1
    number.downto(1) {
        num -> result *= num
    }
    return result
}

//累加
int cal(int number) {
    int result = 0
    number.times {
        num -> result += num
    }
    return result
}

字符串和闭包结合使用

String str = '2 and 3 is 5'

//each遍历
str.each {
//    String temp -> println temp.multiply(2)
    String temp -> println temp
}

//find查找符合条件的第一个,findAll查找所有符合条件的放到集合
println str.find{
    String s -> s.isNumber()
}

def list = str.findAll{
    String s -> s.isNumber()
}
println list.toListString() //[2, 3, 5]

def result = str.any {
    String s -> s.isNumber()    //有一项是数字就返回true
}
println result //true

println str.every { //false
    String s -> s.isNumber()    //每一项都是数字就返回true
}

def list2 = str.collect{
    it.toUpperCase()
}
println list2.toListString()    //[2,  , A, N, D,  , 3,  , I, S,  , 5]

闭包进阶

变量:this、owner、delegate

def scriptClouser = {
    println "this:" + this  //代表闭包定义处的类
    println "owner:" + owner    //代表闭包定义处的类或者对象
    println "delegate:" + delegate  //代表任意对象,默认与owner一致
}
scriptClouser.call()

class Person{//内部类
    def classClouser = {
        println "classClouser this:" + this  //代表闭包定义处的类
        println "classClouser owner:" + owner    //代表闭包定义处的类或者对象
        println "classClouser delegate:" + delegate  //代表任意对象,默认与owner一致
    }

    def say(){
        def classClouser = {
            println "method classClouser this:" + this  //代表闭包定义处的类
            println "method classClouser owner:" + owner    //代表闭包定义处的类或者对象
            println "method classClouser delegate:" + delegate  //代表任意对象,默认与owner一致
        }
        classClouser.call()
    }
}
Person person = new Person()
person.classClouser.call()
person.say()

def nextClouser = {
    def innerClouser = {
        println "innerClouser this:" + this  //代表闭包定义处的类
        println "innerClouser owner:" + owner    //代表闭包定义处的类或者对象
        println "innerClouser delegate:" + delegate  //代表任意对象,默认与owner一致
    }
    innerClouser.delegate = person  //修改delegate
    innerClouser.call()
}
nextClouser.call()

闭包委托策略

class Student {
    String name
    def pretty = {
        "My name is ${name}"
    }
    String toSting(){
        pretty.call()
    }
}
class Teacher {
    String name
}

def stu = new Student(name: 'Sarash')
def tea = new Teacher(name: 'Qndroid')
stu.pretty.delegate = tea
stu.pretty.resolveStrategy = Closure.DELEGATE_FIRST//delegate优先
println stu.toSting()   //My name is Qndroid

2.3、列表list

数组和列表定义方式

def array = [1, 2, 3, 4, 5, 6] as int[]
int[] array2 = [1, 2, 3, 4, 5, 6]
def list = [1, 2, 3, 4, 5, 6]

主要介绍特有的

//排序
def sortList = [1, -4, 5, -6, 2, 3]
//Collections.sort(sortList)
//println sortList    //[-6, -4, 1, 2, 3, 5]
sortList.sort()
println sortList    //[-6, -4, 1, 2, 3, 5]

//自定义排序
//Comparator mc = { a, b ->
//    a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1
//}
//Collections.sort(sortList, mc)
//println sortList    //[1, 2, 3, -4, 5, -6]
sortList.sort { a, b ->
    a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1
}
println sortList    //[1, 2, 3, -4, 5, -6]

//字符串排序
def sortStringList = ['123', 'a', 'groovy']
sortStringList.sort { it -> return it.size() }
println sortStringList  //[a, 123, groovy]

//查找
def findList = [-3, 8, -8, 12, 4, 7]
int result = findList.find { return it % 2 == 0 }
println result  //8
def result2 = findList.findAll { return it % 2 == 0 }
println result2.toListString()  //[8, -8, 12, 4]

def result3 = findList.any { return it % 2 != 0 }
println result3 //true
def result4 = findList.every { return it % 2 != 0 }
println result4 //false

println findList.min()  //-8
println findList.max()  //12

def num = findList.count { return it % 2 == 0 } //符合条件的个数
println num //4

2.4、映射map

定义和基本操作

def colors = [red: 'ff0000', green: '00ff00', blue: '0000ff']
println colors.getClass()   //class java.util.LinkedHashMap
//索引
println colors['red']   //ff0000
println colors.red  //ff0000
//添加
colors.yellow = 'ffff00'
println colors.toMapString()    //[red:ff0000, green:00ff00, blue:0000ff, yellow:ffff00]

其他操作

def students = [
        1: [number: '0001', name: 'zhang', score: 55, sex: 'male'],
        2: [number: '0002', name: 'li', score: 62, sex: 'female'],
        3: [number: '0003', name: 'wang', score: 63, sex: 'female'],
        4: [number: '0004', name: 'zhao', score: 66, sex: 'male']
]
//遍历
students.each {
    def student -> println student.key + ":" + student.value
}
//带索引
students.eachWithIndex {
    def student, int index -> println index + '::' + student.key + ":" + student.value
}
//直接遍历
students.each {
    key, value -> println key + ":" + value
}
students.eachWithIndex {
    key, value, index -> println index + ':::' + key + ":" + value
}
//查找
def entry = students.find { def student ->
    return student.value.score >= 60
}
println entry   //2={number=0002, name=li, score=62, sex=female}

def entry2 = students.findAll { def student ->
    return student.value.score >= 60
}
println entry2
//计数
def count = students.count {
    def student -> return student.value.score >= 60 && student.value.sex == 'male'
}
println count   //1
//查找并筛选
def names = students.findAll {
    def student -> return student.value.score >= 60
}.collect {
    return it.value.name
}
println names   //[li, wang, zhao]
//分组
def group = students.groupBy {
    def student -> return student.value.score >= 60 ? '及格' : '不及格'
}
println group.toMapString()
//排序
def sort = students.sort{
    def stu1 ,def stu2->
        Number num1 = stu1.value.score
        Number num2 = stu2.value.score
        return num1 == num2 ? 0 : num1 < num2 ? -1 : 1
}
println sort.toMapString()

2.5、范围range

定义和使用

def range = 1..10
println range[0]    //1
println range.contains(10)    //true
println range.from    //1
println range.to    //10

//遍历
range.each {
    println it
}
//switch中使用
def result = getGrade(75)
println result
def getGrade(Number number){
    def result
    switch (number){
        case 0..<60:
            result = '不及格'
            break
        case 60..<70:
            result = '及格'
            break
        case 70..<80:
            result = '良好'
            break
        case 80..100:
            result = '优秀'
            break
    }
    return result
}

2.6、面向对象

类、方法、接口

//groovy中默认都是public类型
class Person implements Action{
    String name
    Integer age

    def increasseAge(Integer years) {
        this.age += years
    }

    @Override
    void eat() {}
    @Override
    void drink() {}
    @Override
    void play() {}
}

def person = new Person(name: "zhang", age: 26)
println "name:${person.name},age:${person.age}"//name:zhang,age:26
person.increasseAge(10)
println "name:${person.name},age:${person.age}"//name:zhang,age:36

interface Action{
    void eat()
    void drink()
    void play()
}

trait DefaultAction{
    abstract void eat()
    void play(){
        println 'i can play'
    }
}

元编程

class Person {
    String name
    Integer age

    def increasseAge(Integer years) {
        this.age += years
    }

    //一个方法找不到时候,用它代替
    def invokeMethod(String name, Object args) {
        return "invokeMethod: ${name},${args}"
    }
    //优先级高于invokeMethod
    def methodMissing(String name, Object args) {
        return "methodMissing: ${name},${args}"
    }
}

def person = new Person(name: 'zhang', age: 26)
println person.cry()

//为类动态添加属性
Person.metaClass.sex = 'male'
def person1 = new Person(name: 'zhang', age: 26)
println person1.sex     //male
//为类动态添加方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase() }
def personn2 = new Person(name: 'zhang', age: 26)
println personn2.sexUpperCase()     //MALE
//添加静态方法
Person.metaClass.static.createPerson = {
    String name, int age -> new Person(name: name, age: age)
}
def personn3 = Person.createPerson('li', 18)
println personn3.name + personn3.age  //li18

一次注入,应用程序其他方法都可以使用

ExpandoMetaClass.enableGlobally()

3、高级用法

3.1、json文件处理

转换成json

import groovy.json.JsonOutput
import groovy.json.JsonSlurper

class Person {
    String name
    Integer age
}
//转换成Json
def list = [new Person(name: 'zhang', age: 26),
            new Person(name: 'li', age: 22)]
def json = JsonOutput.toJson(list)
println JsonOutput.prettyPrint(json)
//转成实体对象
def jsonSlpuer = new JsonSlurper()
jsonSlpuer.parseText()

get请求

import groovy.json.JsonSlurper

def response = getNetworkData("http://httpbin.org/get?id=123")
println response.args.id
def getNetworkData(String url){
    def connection = new URL(url).openConnection()
    connection.setRequestMethod('GET')
    connection.connect()
    def response = connection.content.text
    def jsonSlurper = new JsonSlurper()
    return jsonSlurper.parseText(response)
}

3.2、xml读取和生成

解析xml格式数据,创建xml格式数据,都不再详解

3.3、文件操作

读取文件

def file = new File("目标文件")
//方式一
file.eachLine {
    line -> println line
}
//方式二
def text = file.getText()
println text
//方式三
def result = file.readLines()
println result
//方式四,读取部分内容
def reader = file.withReader {
    reader -> char[] buffer = new char[100]
        reader.read(buffer)
        return buffer
}
println reader

拷贝文件

def copy(String sourcePath, String destationPath) {
    try {
        def desFile = new File(destationPath)
        if (!desFile.exists()) {
            desFile.createNewFile()
        }
        new File(sourcePath).withReader {
            reader ->
                def lines = reader.readLines()
                desFile.withWriter {
                    writer ->
                        lines.each {
                            line -> writer.append(line + "\r\n")
                        }
                }
        }
        return true
    } catch (Exception e) {

    }
}

对象的读写

def saveObject(Object object, String path) {
    try {
        def desFile = new File(path)
        if (!desFile.exists()) {
            desFile.createNewFile()
        }
        desFile.withObjectOutputStream {
            out -> out.writeObject(object)
        }
        return true
    } catch (Exception e) {

    }
    return false
}

def readObject(String path) {
    def obj = null
    try {
        def file = new File(path)
        if (file == null || !file.exists()) return null
        file.withObjectInputStream {
            input -> obj = input.readObject()
        }
    } catch (Exception e) {

    }
    return obj
}

4、Gradle介绍

Gradle用于构建应用程序,使用Groovy核心语法。

在Terminal中执行

gradlew clean	//win
gradlew build	//win

./gradlew clean	//mac
./gradlew build	//mac

gradle的生命周期

initialization初始化阶段:根据settings.gradle解析整个工程中所有的Project,构建所有的Project对应的project对象。
Configuration配置阶段:解析所有的projects对象中的task,构建好所有的task的拓扑图
Excution执行阶段:执行具体的task及其依赖task

生命周期监听

//配置阶段开始前的监听回调
this.beforeEvaluate {
    println '------配置阶段开始------'
}
//配置阶段完成以后的监听回调
this.afterEvaluate {
    println '------配置阶段完成------'
}
//gradle执行完毕后的回调监听
this.gradle.buildFinished {
    println '------gradle执行完毕------'
}
//等同beforeEvaluate
this.gradle.beforeProject {}
//等同afterEvaluate
this.gradle.afterProject {}

5、Project

查看Project的个数

gradlew projects
./gradlew projects	//mac

5.1、Project相关API

在最外层的根的build.gradle中

this.getProjects()
def getProjects(){
    //只输全部projects
    this.getAllprojects().eachWithIndex {
        Project project, int index ->
        if (index ==0){
            println "this is Root project:${project.name}"
        } else {
            println "this is project:${project.name}"
        }
    }
    //只输出子projects
    this.getSubprojects().eachWithIndex {
        Project project, int index ->
            println "this is project:${project.name}"
    }
    //只输出根projects
    println "this is Root project:" + this.getRootProject().name
}

在module的build.gradle中

//只输出父projects
println "this is parent project:" + this.getParent().name

根project中可以配置module的配置

//根project配置module为app的配置
project('app') {
    Project project ->
        println project.name    //app
        apply plugin: 'com.android.application'
        group 'com.tea'
        version '1.0.0-release'
        dependencies {}
        android {}
}

配置当前节点工程和subproject的所有project

//配置当前节点工程和subproject的所有project
allprojects {
    group 'com.tea'
    version '1.0.0-release'
}
println project('app').group

不包括当前节点工程,只包括他的subproject

//不包括当前节点工程,只包括他的subproject
subprojects {
    Project project ->
        if (project.plugins.hasPlugin('com.android.library')) {
            apply from: '../publistTOMaven.gradle'
        }
}

5.2、属性相关API

定义扩展属性

ext{}

所以提供扩展属性定义方式:

方式一:

可以在根build中定义

ext {
    compileSdkVersion = 28
    cardview = 'com.android.support:cardview-v7:28.0.0'
}

然后在需要用的build中引用

compileSdkVersion this.rootProject.compileSdkVersion
implementation this.cardview

方式二:

和根build同级定义common.gradle

ext {

    android = [compileSdkVersion: 28,
               buildToolsVersion: '26.0.0',
               applicationId    : 'com.tea',
               minSdkVersion    : 16,
               targetSdkVersion : 26,
               versionCode      : 1,
               versionName      : '1.0.0',
               multiDexEnabled  : true]

    signConfigs = ['storeFile'    : 'tea.jks',
                   'storePassword': 'tea123456',
                   'keyAlias'     : 'android',
                   'keyPassword'  : 'tea123456']

    java = ['javaVersion': JavaVersion.VERSION_1_8]

    dependence = ['libCardview' : 'com.android.support:cardview-v7:28.0.0',
                  'libAppcompat': 'com.android.support:appcompat-v7:28.0.0']
}

在根build中引入

apply from: this.file('common.gradle')

在需要的build中使用

compileSdkVersion rootProject.ext.android.compileSdkVersion
implementation rootProject.ext.dependence.libCardview

方式三:

在gradle.properties中定义key:value形式

mCompileSdkVersion = 28

build中使用,默认都是字符串,需要转换

compileSdkVersion mCompileSdkVersion.toInteger()

5.3、file相关API

文件路径获取

println getRootDir().absolutePath
println getBuildDir().absolutePath
println getProjectDir().absolutePath

文件定位

apply from: this.file('common.gradle')

println getContent('common.gradle')
def getContent(String path){
    try {
        //路径是相对于当前project查找
        def file = file(path)
        return file.text
    }catch (GradleException e){
        println "not found"
    }
    return null
}

文件拷贝,在app的build中拷贝文件或者文件夹

copy {
    from file('build/outputs/apk/')
    into getRootProject().getBuildDir().path + '/apk/'
    exclude {}//补拷贝的文件
    rename {}//重命名
}

文件树

fileTree('src/main/assets/'){FileTree fileTree ->
    fileTree.visit {FileTreeElement element ->
        println element.file.name
        copy {
            from element.file
            into getRootProject().getBuildDir().path + '/test/'
        }
    }
}

5.4、依赖相关API

依赖

buildscript {	
    //配置工程的仓库地址
    repositories {	}
    //配置工程的gradle插件依赖地址,app中的是项目的第三库依赖
    dependencies {	}
}

依赖冲突常用解决办法

compile ('rootProject.ext.dependence.libAutoScrollViewPager') {
    exclude module: 'support-v4'//排除依赖
    exclude group: 'com.android.support'
    transitive false//禁止传递依赖
}

provided只在编译起作用,占位编译。

5.5、外部命令API

调用系统指令,执行./gradlew apkcopy

task(name: 'apkcopy') {
    doLast {
        def srcPath = this.buildDir.path + '/outputs/apk'
        def destPath = './target/apk'
        def command = "mv -f ${srcPath} ${destPath}"
        exec {
            try {
                executable 'bash'
                args '-c', command
                println 'this command exec success'
            }catch(GradleException e){
                println 'this command exec error'
            }
        }
    }
}

调用脚本

task stopTomcat(type:Exec) {
    //dir
    workingDir '../tomcat/bin'
    //windows
    commandLine 'cmd', '/c', 'stop.bat'
    //linux
    commandLine './stop.sh'
}

6、task

两种定义方式

task helloTask (group: 'com.tea',description: 'study'){
    println '---------helloTask'
}

this.tasks.create(name : 'helloTask2'){
    setGroup('com.tea')
    setDescription('study')
    println '---------helloTask2'
}

doFirst和doLast

task helloTask (group: 'com.tea',description: 'study'){
    println '---------helloTask'
    doFirst {
        println '---------helloTask---doFirst'
    }
}
helloTask.doFirst{
    println '---------helloTask---doFirst2'//比闭包的先执行
}

统计Build时长

def startTime,endTime
this.afterEvaluate {Project project ->
    def  preBuildTask = project.tasks.getByName('preBuild')
    preBuildTask.doFirst {
        startTime = System.currentTimeMillis()
        println "==============:" + startTime
    }
    def buildTask = project.tasks.getByName('build')
    buildTask.doLast {
        endTime = System.currentTimeMillis()
        println "==============:" + endTime
        println "==============:" + (endTime - startTime)
    }
}

依赖

task taskX {
    doLast {
        println "taskX"
    }
}
task taskY {
    doLast {
        println "taskY"
    }
}
//动态依赖
task taskZ {
    dependsOn this.tasks.findAll {
        task ->
            println task.name
            return task.name.startsWith('taskX')
    }
    doLast {
        println "taskZ"
    }
}
//静态依赖
task taskZ(dependsOn: [taskX, taskY]) {
    dependsOn this.tasks.findAll {
        task -> return task.name.startsWith('lib')
    }
    doLast {
        println "taskZ"
    }
}
//或者
taskZ.dependsOn(taskX, taskY)

输入输出

task writeTask{
    //输入
    inputs.property("key","value")
    def data = inputs.getProperties()
    //输出
    outputs.file 文件
    File file = outputs.getFiles().getSingleFile()
}

执行顺序指定

mustRunAfter

7、其他模块

7.1、SourceSet

修改资源路径

sourceSets {
    main{
        jniLibs.srcDirs = ['libs']//修改so库文件位置
    }
}

给res分模块分包

sourceSets {
    main{
        res.srcDirs = ['src/main/res',
                       'src/main/res-ad',
                       'src/main/res-tea']
    }
}

7.2、自定义plugin


main下的java替换成groovy,新建.groovy类:

class GradleStudyPlugin implements Plugin<Project>{
    @Override
    void apply (Project project){
        project.extensions.create('comTea',xxx(groovy类))	
    }

}

自定义task的类

class xxxxx extend DefaultTask{
    @TaskAction
    void doAction(){
        //执行于gradle执行阶段的代码
    }
}

main/resources/META-INF.gradle/包名.properties:

implementation-class=包名.类名

build.gradle为:

apply plugin: 'groovy'
sourceSets {
    main{
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}

引用和传参

apply plugin: '包名'

comTea{
    //传参
}

7.3、修改apk名字

app的build中

this.afterEvaluate {
    this.android.applicationVariants.all { variant ->
        def output = variant.outputs.first()
        def apkName = "app-${variant.baseName}" + "-${variant.versionName}.apk"
        output.outputFile = new File(output.outputFile.parent,apkName)
        println "------------------"
    }
} 

8、Jenkins

java -jar jenkins.war 

Android实战应用

buildTypes和productFlavors


和main同级别,同包名,创建文件,区别使用debug还是release。可以用来实现类似gradle调用java类。


implementation


implementation:不会传递依赖;compile / api:会传递依赖;api 是 compile 的替代品。当依赖被传递时,二级依赖的改动会导致0级项目重新编译;当依赖不传递时,二级依赖的改动不会导致 0 级项目重新编译。


plugin


android{}的内容就是对apply plugin: 'com.android.application'的配置。

参考上述7.2、自定义plugin

新建Module-Java Library-buildSrc模块

创建目录\buildSrc\src\main\resources\META-INF\gradle-plugins,创建文件xxx.properties

implementation-class=com.plugin.demo.PluginDemo

目录buildSrc\src\main\groovy\com\plugin\demo创建文件PluginDemo.groovy

import com.android.build.gradle.BaseExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
public class PluginDemo implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        def extension = project.extensions.create('yyyy', ExtensionDemo)
        project.afterEvaluate {
            println "Hello ${extension.name}!"//Hello zzzzz
        }
        //def transform = new TransformDemo()
        //def baseExtension = project.extensions.getByType(BaseExtension)
        //baseExtension.registerTransform(transform)
    }
}

创建文件ExtensionDemo.groovy

public class ExtensionDemo {
    def name = "Author";
}

在app的build中使用plugin

apply plugin: 'xxx'

yyyy {
    name 'zzzzz'
}

关于 buildSrc 目录:这是 gradle 的一个特殊目录,这个目录的 build.gradle 会自动被执行,即使不配配置进settings.gradle。buildSrc 的执行早于任何一个 project,也早于 settings.gradle。它是一个独立的存在。 buildSrc 所配置出来的 Plugin 会被自动添加到编译过程中的每一个 project 的 classpath,因此它们才可以直接使用 apply plugin: 'xxx' 的方式来便捷应用这些 plugin。

settings.gradle 中如果配置了 ‘:buildSrc’ ,buildSrc 目录就会被当做是子 Project ,因此会被执行两遍。所以在 settings.gradle 里面应该删掉 :buildSrc 的配置。


Transform


Transform是由 Android 提供的,在项目构建过程中把编译后的文件(jar文件和 class文件)添加自定义的中间处理过程的工具。下面代码只是把编译完的内容原封不动搬运到目标位置,没有实际用处。要修改字节码,需要引入其他工具,例如 javassist。

新建TransformDemo.groovy

import com.android.build.api.transform.Format
import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformException
import com.android.build.api.transform.TransformInvocation
import com.android.build.gradle.internal.pipeline.TransformManager
import com.android.utils.FileUtils;

public class TransformDemo extends Transform {
    @Override
    String getName() {
        return "hencoderTransform"
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {

        def inputs = transformInvocation.inputs
        def outputProvider = transformInvocation.outputProvider

        inputs.each {
            it.jarInputs.each {
                File dest = outputProvider.getContentLocation(it.name, it.contentTypes, it.scopes, Format.JAR)
                FileUtils.copyFile(it.file, dest)
            }

            it.directoryInputs.each {
                File dest = outputProvider.getContentLocation(it.name, it.contentTypes, it.scopes, Format.DIRECTORY)
                FileUtils.copyDirectory(it.file, dest)
            }
        }
    }
}

buildSrc-build中改为:

repositories {
    google()
    jcenter()
}

dependencies {
    implementation 'com.android.tools.build:gradle:3.2.1'
}

PluginDemo.groovy中添加代码

def transform = new TransformDemo()
def baseExtension = project.extensions.getByType(BaseExtension)
baseExtension.registerTransform(transform)

修改app-build中的plugin放在android{}之后。

示例:https://github.com/liangzhitao/consuming-collector



文章作者:
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 !
  目录