Gradle 基础知识

本文将对Gradle的一些基本概念、用法进行总结,从而避免自己在Android开发过程中的“会而不知所以然”,关于Gradle的高阶用法可以见参考,本文就不再赘述;

基本概念

Wrapper

为了保证gradle版本的一致性,比如我们下载某个Android工程,编译运行前,wrapper会检查你本地是否存在gradle-wrapper.properties文件中声明的gradle版本,如果不存在,就会去下载,通常是个gradlew配合一起使用的,如下示例,可以帮助你更好的理解wrapper的概念;

[min@TATEMIN-MB0:] gradle $ mkdir wrapper-demo  # 创建一个空的wrapper-demo
[min@TATEMIN-MB0:] gradle $ cd wrapper-demo/
[min@TATEMIN-MB0:] wrapper-demo $ gradle -v     # 查看当前gradle的版本

------------------------------------------------------------
Gradle 5.4.1
------------------------------------------------------------

Build time:   2019-04-26 08:14:42 UTC
Revision:     261d171646b36a6a28d5a19a69676cd098a4c19d

Kotlin:       1.3.21
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          1.8.0_241 (Oracle Corporation 25.241-b07)
OS:           Mac OS X 10.15.4 x86_64

[min@TATEMIN-MB0:] wrapper-demo $ gradle wrapper # 创建一个gradle wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
[min@TATEMIN-MB0:] wrapper-demo $ tree
.
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

2 directories, 4 files
# 查看wrapper的内容,可以看到distributionUrl的版本号和我们本地的对齐,此工程如果那运作在一台没有安装过gradle-5.4.1的设备上,会先去下载gradle-5.4.1对应的包,此过程由gradlew+gradle-wrapper.jar完成;
[min@TATEMIN-MB0:] wrapper-demo $ cat gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

GradleUserHome

在Mac/Linux系统上,此目录即为~/.gradle目录,可以理解为gradle的workspace。

Daemon

因为JVM启动速度很慢,大约每次启动在10s左右,所以gradle为了解决这个问题,将gradle设计为如下结构:

gradle-deamon

大体的意思即使说,在启动gradle后会同时启动两个进程,一个Client,一个Daemon,Client负责具体的交互,比如命令的接收、日志的打印等等,Daemon负责具体的编译工作并和Client完成交互,Client端推出后,Daemon并不立即退出,如果期间没有新的Client发消息进来,会存活3小时左右,这样就避免了每次gradle启动时等待JVM启动的耗时,另外如果当前启动的Client版本和Daemon不一致,会重新启动一个Deamon

Daemon 4.0以前,CI相关编译建议加上--no-daemon,因为此时Daemon并不稳定,后续版本无此问题。

Groovy基础

动态调用和MOP

MOP:元对象协议。由 Groovy 语言中的一种协议。该协议的出现为元编程提供了优雅的解决方案。而 MOP 机制的核心就是 MetaClass。
元编程:编写能够操作程序的程序,也包括操作程序自身,示例如下:

string = 'hello'
targetMethod = string.metaClass.getMetaMethod('toUpperCase')
println(targetMethod.invoke(string))

闭包

  • 闭包是一个开放,匿名的代码块,可以接受参数,返回值并分配给变量

  • 闭包定义:{ [closureParameters -> ] statements },示例:

    //执行一句话  
    { printf 'Hello World' }                                   
        
    //闭包有默认参数it,且不用申明      
    { println it }                   
    
    //闭包有默认参数it,申明了也无所谓                
    { it -> println it }      
        
    // name是自定义的参数名  
    { name -> println name }                 
    
     //多个参数的闭包
    { String x, int y ->                                
        println "hey ${x} the value is ${y}"    
    }
    
  • Android示例:

    def android(closure) = {
        closure()
    }
    
    def ext(closure) = {
        closure()
    }
    
    android {
        ext {
            println("i am ext")
        }
    }
    

Gradle 构建

主要理解gradle的核心模型

  • Project

    每个Gradle构建都由一个或多个Project组成。

  • Task

    每个Project由一个或多个Task组成,Task代表构建执行的一些原子工作,比如编译某些类、创建JAR、生成Javadoc等等;

  • Lifecycle与Hook

    Gradle构建的声明周期都分为三个不同的阶段.

    • Initialization

      Gradle支持单项目和多项目构建. 在初始化阶段,Gradle确定将要参与构建的Project,并为每个Project创建一个Project实例(构建文件与Gradle交互的主要API.)

    • Configuration

      在此阶段,将配置项目对象,执行作为构建一部分的所有项目的构建脚本.

    • Execution

      Gradle确定要在配置阶段创建和配置的任务子集. 子集由传递给gradle命令的任务名称参数和当前目录确定. 然后Gradle执行每个选定的任务.

下面是一个非常好的例子可以理解一下:

task("hello_world") {
    println("configuration")

    doLast {
        println("execution task")
    }
}

(1..10).each { i ->
    task("task_${i}") {
        int index = i
        if (index % 2 == 0) {
            dependsOn("hello_world")
        }

        doLast {
            println("executing task_${index}")
        }
    }
}

afterEvaluate {
    println("after evaluate")
}

此脚本最后执行结果如下:

[min@TATEMIN-MB0:] wrapper-demo $ ./gradlew task_2

> Configure project :  # Configuration阶段
configuration
after evaluate

> Task :hello_world    # Execution阶段
execution task

> Task :task_2               # Execution阶段
executing task_2

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

参考

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