Gradle插件相关知识

Gradle插件

插件工程结构

Gradle插件的工程结构如下图所示:

Paste_Image.png

这个工程既可以作为单独的工程,也可以作为子工程存在,工程目录分为groovy和resources两个目录,分别存放插件groovy文件和配置文件。

build.gradle

Paste_Image.png

还需要添加以下配置保证插件在不同版本的java平台正常运行

Paste_Image.png

插件代码

声明Groovy文件,implements Plugin<Project>,在void apply(Project project) 方法中实现插件代码。在resources目录下META-INF.gradle-plugins创建一个properties文件,将Groovy文件的包名加类名声明在properties文件中,例如com.husor.android.makechannel.properties文件中:

implementation-class=com.husor.android.makechannel.MakeChannelPlugin

这就代表插件名为com.husor.android.makechannel,具体实现内容在MakeChannelPlugin文件中。

在apply方法中传入了project对象,表示我可以使用project对象的任意api,project对象可以获取到任意的工程中的文件、任务,那么能做的事情就很多了,比如复制文件、上传文件,android插件的打包过程就是通过android_sdk/tools下的工具,对当前工程中的各种文件进行编译、签名、对齐、打包等操作的。希望下一篇文章,可以学习一下安卓的打包过程。

插件发布

Paste_Image.png

上传到本地testRepo目录下的插件包地址为com.beibei.android:makechannel:1.0.0-SNAPSHOT

上传到maven服务的插件包地址为com.beibei.android:makechannel:1.0.0

注意上传到本地的artifactId取决于project的name,而当前name为makechannel,上传到maven库的artifactId取决于声明

插件使用

Paste_Image.png

Groovy

在学习Gradle之前,首先要了解Groovy,Groovy是一种脚本语言,基于Java又拓展了java的特性,欢迎参考官方文档 http://www.groovy-lang.org/documentation.html ,深入学习起来还是有一大片天地的,接下来我简单讲讲我理解的一些基本特性。

首先看一段代码:

task testGroovy << {
    def var1 = 1024
    println var1

    var1 = "林帅"
    println var1
    println "my name is $var1"

    println test1();

    def var2 = 5
    println var2.class

    var2 = 5.5
    println var2.class

    var2 = 5L
    println var2.class

    var2 = 5D
    println var2.class

    var2 = 'hehe'
    println var2.class

    var2 = false
    println var2.class

    def demoList = [121, 3.14, 'hello', false, null] // 使用[]定义,元素之间用,隔开
    println demoList.size // 获取集合大小
    println demoList[2] // 获取index为2的元素
    // 在结尾添加元素的两种写法
    demoList.add(100)
    demoList << 100
    // 在指定位置添加元素,原本index大于等于3的元素往后退一位
    demoList.add(3, 100)
    demoList.remove(0) // 删除指定index的元素
    demoList -= [3.14, false] // 删除某集合的元素
    // demoList.clear() // 清空集合
    // 使用集合直接调用.each可以对集合进行遍历
    demoList.each {
        println it // it是迭代过程中的每一个元素
    }

    def demoMap = ['name': '林帅', 'age': 18, 'isGay': false]
    println demoMap.size() // 获取map大小
    println demoMap.name // 通过key获取值
    demoMap << ['hehe': '777'] // 添加元素
    demoMap['haha'] = '888' // 添加元素
    // 遍历map
    demoMap.each {
        println it.key
        println it.value
    }

    pick(10, { a, b ->
        if (a % 2 == 0)
            println b * a
    })
    println testMethod(4, 5)

}

def String test1() {
    return "xiaolinzi"
}

def pick(n, closure) {
    for (i in 1..n) {
        closure(i, 2)
    }
}
//可以不写返回类型,不写参数类型,return可以不写,默认取最后一行
def testMethod(a, b) {
    println a + b
    3333
}
1024
林帅
my name is 林帅
xiaolinzi
class java.lang.Integer
class java.math.BigDecimal
class java.lang.Long
class java.lang.Double
class java.lang.String
class java.lang.Boolean
// list
5
hello
hello
100
null
100
100
// map
3
林帅
name
林帅
age
18
isGay
false
hehe
777
haha
888
// end
4
8
12
16
20
9
3333

1、弱类型,不用定义类型,类型之间也可以互相赋值,使用def标识

2、有分号或者没有都可以

3、方法有默认返回最后一行的数据,当最后一行没有时返回空,方法可以缺省返回值类型,默认public

4、在字符串中使用美元符访问变量,单引号和双引号的含义相同,三引号代表多行字符串

5、使用groovyc进行编译

6、Groovy的闭包是一个代码块或者方法指针,代码在某处被定义然后在其后的调用处执行

Groovy语法是在java预发基础上的升级版,有些特性是对java语法的补充提升,多用一下就可以理解了。

Gradle

首先搬官方文档 https://docs.gradle.org/current/userguide/userguide.html ,这个文档写的非常清楚,真的应该好好的读一遍,我只读了前几章,如果以后有机会一定再深入的学习一番。

Gradle的实质是配置脚本,执行一种类型的配置脚本时就会创建一个关联的对象,譬如执行Build script脚本就会创建一个Project对象,这个对象其实就是Gradle的代理对象。

Gradle的三种主要对象解释如下:

  • Project对象:每个build.gradle会转换成一个Project对象。
  • Gradle对象:构建初始化时创建,整个构建执行过程中只有这么一个对象,一般很少去修改这个默认配置脚本。
  • Settings对象:每个settings.gradle会转换成一个Settings对象。

整个构建过程如图所示:

Paste_Image.png
settings.gradle

放在工程的根目录,在多工程构建中用于标识对应的多工程module,可以动态的修改module的projectDir等信息。在工程构建的初始阶段为当前项目创建一个Settings类型的实例,创建项目层级结构的Project对象实例。

build.gradle

gradle构建的第二步是执行.gradle目录下的Init script脚本,为接下来的Build script做一些准备工作,一般我们不会修改这个脚本。

接下来第三步就是执行各个工程目录下的build.gradle脚本,将各个task任务及关系进行确认,达成最终的构建目标生成。

gradle构建最重要的就是理解task,其实插件本身就是一个task合集,插件是为了更好的复用和迁移代码,其实和写在build.gradle中是没有任何区别的。

常用的gradle command-line

1、name缩写 gradle aR => gradle assembleRelease

2、gradle -q projects

gradle -q tasks

gradle -q dependencies

前面都可以加上module名

3、-D system property

-P project property

-q Log error only

-i 查看log信息

-d 查看debug信息

https://docs.gradle.org/current/userguide/gradle_command_line.html

task

最后整理一下任务相关,可能整理不完善,后续不断加进来。

1、任务定义

task hello {
    doLast {
        println 'Hello world!'
    }
}
task hello << { // 快捷定义
    println 'Hello world!'
}

2、任务依赖

task intro(dependsOn: hello) {
    doLast {
        println "I'm Gradle"
    }
}

3、动态添加任务目标

hello.doLast {
    println "This is append hello"
}

4、properties声明

ext.pro1 = [ // extra properties
             "test1": "properyTest1",
             "test2": "properyTest2"
]
ext {
    pro2 = "property2"
}
task testProperty { // 任务声明
    ext.myProperty = "myValue"
    doLast {
        println hello.myProperty
        println pro1.test1
        println pro1.test2
        println pro2
        println project.properties.get("test")
        println System.getProperty("test")
    }
}

使用 gradle testProperty -Ptest=test1 -Dtest=test2 试试看吧

5、default task定义

defaultTasks 'hello' 

默认执行hello task

6、理解gradle.taskGraph

gradle.taskGraph.whenReady { taskGraph ->
    println taskGraph.allTasks
}

taskGraph对象包含当前目标任务所包含所有的任务对象

7、project api

project Project The Project instance
name String The name of the project directory.
path String The absolute path of the project.
description String A description for the project.
projectDir File The directory containing the build script.
buildDir File *projectDir*/build
group Object unspecified
version Object unspecified

8、类型任务定义

task('hello') {
    doLast {
        println "hello"
    }
}
task('copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}
tasks.create(name: 'hello') {
    doLast {
        println "hello"
    }
}
tasks.create(name: 'copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

9、File处理

fileCollection 当前路径下的File Set

fileTree 得到一个所有文件的列表

task testFiles {
    project.files(project.buildDir.listFiles()).each {
        println it.name
    }
    println("**********************")
    FileTree tree = fileTree(project.buildDir)
    tree.include 'outputs/aar/*.aar'
    tree.exclude '*/*/*release*' // 这里必须是路径
    tree.each {
        println it.name
    }
}

10、依赖管理

https://docs.gradle.org/current/userguide/dependency_management.html

中央仓库:

  • mavenCentral,表示依赖是从Central Maven 2 仓库中获取的。
  • jcenter,表示依赖是从Bintary’s JCenter Maven 仓库中获取的。
  • mavenLocal,表示依赖是从本地的Maven仓库中获取的。
  • 自定义maven仓库
  • flatDir 表明系统将在lib目录下搜索依赖
repositories {
    maven {
        url "http://maven.petrikainulainen.net/repo"
        url  uri('/Users/xiaolinzi/testRepo') // 本地仓库
    }
    mavenCentral()
    flatDir {
        dirs 'libA', 'libB'
    }
}

依赖分类:

  • 当项目的源代码被编译时,compile配置项中的依赖是必须的。
  • runtime 配置项中包含的依赖在运行时是必须的。
  • testCompile 配置项中包含的依赖在编译项目的测试代码时是必须的。
  • testRuntime 配置项中包含的依赖在运行测试代码时是必须的。
  • archives 配置项中包含项目生成的文件(如Jar文件)。
  • default 配置项中包含运行时必须的依赖。
  • 在android还会用到provided表示在运行时依赖,编译时取消依赖

声明依赖的方式

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '2.5'
    compile 'org.springframework:spring-core:2.5'
    compile('org.hibernate:hibernate:3.0.5') {
        transitive = true // 代表传递依赖被打开,默认打开
    }
    compile module("org.codehaus.groovy:groovy:2.4.7") { // 直接声明传递依赖的版本
        dependency("commons-cli:commons-cli:1.0") {
            transitive = false
        }
        module(group: 'org.apache.ant', name: 'ant', version: '1.9.6') {
            dependencies "org.apache.ant:ant-launcher:1.9.6@jar",
                         "org.apache.ant:ant-junit:1.9.6"
        }
    }
    compile project(':shared') // 依赖一个本地project
    compile fileTree(dir: 'libs', include: '*.jar') // 依赖文件
    compile gradleApi() //
    compile localGroovy()
}

依赖冲突

去除依赖

configurations {
    compile.exclude module: 'commons'
    all*.exclude group: 'org.gradle.test.excludes', module: 'reports'
}

dependencies {
    compile("org.gradle.test.excludes:api:1.0") {
        exclude module: 'shared'
    }
}

文档上还有很多东西没看透彻,以后慢慢补充吧,先写成这样。。>_<

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • Gradle内核本身提供的自动化构建功能十分有限,所有实际的功能都是通过插件的形势提供的,如编译Java代码的功能...
    JackMeGo阅读 953评论 0 2
  • 目前为止,我们已经学习了如何修改Gradle构建属性,以及如何运行任务。本章,我们会深入了解这些属性,并且创建我们...
    sollian阅读 2,593评论 0 8
  • 这篇文章讲给大家带来gradle打包系列中的高级用法-自己动手编写gradle插件。我们平常在做安卓开发时,都会在...
    呆萌狗和求疵喵阅读 15,969评论 22 80