Gradle快速入门

Gradle快速入门

1,Gradle概述

Gradle 是一个开源构建自动化工具,其设计足够灵活,可以构建几乎任何类型的软件。Gradle是基于Grovvy语言,运行在JVM之上。Gradle借鉴了Maven和Ant等先辈的设计思想,因此很容易从Maven或Ant切换成Gradle构建。

同时Gradle非常易于扩展,因此很方便实现客制化的构建需求。

2,Projects&Tasks

任何一个Gradle构建都是有一个或多个projects组成。每个project由多个task组成。每个task都代表了构建执行过程中的一个原子性操作。

2.1.1,Task

2.1.1.1,Task的创建

静态定义:

 
  1. //方式1
  2. task myTask {
  3. println '在配置阶段执行'
  4. doFirst {
  5. println '在执行Action前执行'
  6. }
  7. doLast {
  8. println '在执行Action后执行'
  9. }
  10. }
  11. //方式2
  12. tasks.register("myTask") {
  13. println '在配置阶段执行'
  14. doFirst {
  15. println '在执行Action前执行'
  16. }
  17. doLast {
  18. println '在执行Action后执行'
  19. }
  20. }

上面的脚本采用闭包的方式定义了一个Task。

<< 等操作无在Gradle 4.x中被弃用,在Gralde 5.x中被移出。新版本请用doLast,doFirst替代。

动态定义:

 
  1. project.afterEvaluate {
  2. task xxxx {
  3. println 'xxxx'
  4. }
  5. }

定义属性

 
  1. task myTask {
  2. ext.myProperty = value
  3. }
  4. task printTaskProperty {
  5. println myTask.myProperty
  6. }

定义默认任务

 
  1. defaultTasks 'clean', 'run'
  2. task clean {
  3. println 'clean'
  4. }
  5. task run {
  6. println 'run'
  7. }
  8. task normalTask {
  9. println 'normal task'
  10. }

执行\>gradle -q输出:

 
  1. clean
  2. run

其他属性:

关键字描述
type基于一个存在的task来创建,和继承差不多意思
description配置任务的描述
group用于配置任务的分组
action添加action

2.1.1.2,任务继承和覆盖

 
  1. //继承
  2. task myCopy(type: Copy) {
  3. }
  4. //覆盖
  5. task copy(overwrite: true) {
  6. }

注意:

1,task的名字必须和被覆盖的task名字保持一致
2,覆盖操作,不仅会覆盖掉原先task的所有action,而且会覆盖原先task指定的type类型,还会覆盖掉所有和原先task相关的依赖关系。被覆盖的依赖关系不仅包含原先的task对其他task的依赖,还包含其他task对原先task的依赖,所有的和原先task相关的依赖关系都会被移除。当然,可以在overwrite之后重新定义新的依赖关系。

3,如果定义overwrite的task在这之前并没有被创建,那么gradle会忽略这个属性,等同于创建一个新的task

2.1.1.3,任务依赖

关键字作用备注
dependsOnA.dependsOn B:执行A之前如果B没有执行则需要先执行B,执行B则无法执行A如果B已经执行了,则B不会再次执行
finalizedByA.finalizedBy B:每次执行A,B都会在其后执行如果B已经执行了,则B不会再次执行

2.1.1.4,任务排序

关键字作用备注
mustRunAfterA.mustRunAfter B: A必须在B之后执行不会改变AB间的依赖关系
shouldRunAfterA.shouldRunAfter B: A应该在B之后执行不会改变AB间的依赖关系

1,任务排序不改变任务间的依赖关系。比如A.mustRunAfter B, 如果单独执行A,B是不会执行的,任务排序只有在AB同时执行的情况下,保证AB间的执行顺序而已。

2,当存在循环排序时,shouldRunAfter会被忽略

2.1.1.5,任务运行

Gradle无法直接运行Task,需要将Task挂载到某个Hock点上,详细见任务依赖

或者直接在命令行调用:

 
  1. gradle -q myTask

2.2,Project

project可以简单理解成build.gradle文件解析后对应的对象。我们知道初始化阶段,Gradle会从setting.gradle文件中解析生成项目结构。整个项目会解析成一个project对象,同时settings.gradle中所有include的模块也会解析成一个个project对象。Gradle以树形结构管理整个项目。因此可以看出Gradle通过project统筹管理项目和子模块。也可以认为一个project对应一个构建输出。app module对应的输出类型是application即apk文件,Android libaray对应的输出类型是aar,java libaray对应的输出是jar。

这里把project理解成build.gradle文件解析后对应的对象是一种简便方法,实际上两者有稍微差别。具体有关ProjectScript和Project的细节不在本文中展开

2.2.1,Gradle项目通用目录结构

 
  1. RootProject
  2. ├───build.gradle //顶层项目配置,通用配置,Gradle插件仓库,依赖仓库配置等
  3. ├───gradle.properties //配置文件
  4. ├───gradlew
  5. ├───gradlew.bat //Gradlew可执行文件
  6. ├───local.properties //本地配置文件,sdk路径等
  7. ├───settings.gradle //定义了哪些模块会参与编译,单个module可以无需此文件。新版本Gradle还可以在此文件中定义插件加载策略
  8. ├───app //主模块,名字'app'可自定义
  9. │ ├───build.gradle //模块级gradle配置文件
  10. │ ├───libs
  11. │ └───src
  12. |
  13. ├───module1 //子模块
  14. │ ├───build.gradle
  15. │ ├───libs
  16. │ └───src
  17. └───module12 //子模块
  18. ├───build.gradle
  19. ├───libs
  20. └───src

3,Gradle构建生命周期

Gradle的构建可分为三个阶段:初始化阶段,配置阶段,执行阶段

3.1,初始化阶段

初始化阶段是Gradle创建项目的层次结构,并为每个项目创建一个Peoject实例。与初始化阶段相关的脚本文件是settings.gradle文件(包括<USER_HOME>/.gradle/init.d目录下的所有.gradle脚本文件)。一个settings.gradle文件对应一个Settings对象。可以通过以下代码向Gradle的构建过程添加监听:

 
  1. gradle.addBuildListener(new BuildListener() {
  2. void buildStarted(Gradle var1) {
  3. println '开始构建'
  4. }
  5. void settingsEvaluated(Settings var1) {
  6. println 'settings解析完成(settins.gradle中代码执行完毕)'
  7. }
  8. void projectsLoaded(Gradle var1) {
  9. println '项目结构加载完成,初始化阶段结束'
  10. }
  11. void projectsEvaluated(Gradle var1) {
  12. println '所有项目配置完成,配置阶段结束'
  13. }
  14. void buildFinished(BuildResult var1) {
  15. println '执行阶段完成,构建结束 '
  16. }
  17. })

实际上buildStarted回调总是收不到的,因为我们的注册时机太晚了,Gradle已经开始构建了。

3.2,配置阶段

配置阶段主要是执行各项目(模块)下的build.gradle脚本,完成Project的配置,比如:

  • 应用自插件(apply plugin: 'xxx')
  • 配置插件属性(android{ compileSdkVersion 25 ...}
  • 构造Task任务的依赖关系图。

配置阶段执行的代码包括build.gralde中的各种语句、闭包以及Task中的配置段语句。

此阶段一个重要回调是afterEvaluate。通过此回调,可以查找动态注册的Task(包括根据构建风味动态生成的Task等)。

 
  1. project.afterEvaluate {
  2. def android = project.extensions.findByName('android')
  3. android.getApplicationVariants().all { def variant ->
  4. def task = tasks.findByName("assemble${variant.getName().capitalize()}")
  5. }
  6. }

无论执行Gradle的任何命令,初始化阶段和配置阶段的代码都会被执行

3.3,执行阶段

执行阶段Gradle会根据Task依赖关系的有向无环图挨个执行各Task。如果Gradle命令中指定了Task,则Gradle会执行以此Task为起点的所有Task,如果没有指定,则会执行默认Task为起点的所有任务。

3.4,自定义构建过程

Gradle提供了非常多的钩子方法供开发人员自定义构建过程中的行为,整个流程见下图:

可以通过如下代码添加监听:

 
  1. gradle.settingsEvaluated { setting ->
  2. //xxx
  3. }
  4. gradle.projectsLoaded {
  5. //xxx
  6. }

注意:如果要hook初始化阶段的生命周期,需要将注册的代码提前到setting.gradle中,否则会因为错误生命周期而无法触发回调。

4,Gradle全局变量和脚本复用

在一些多模块的大型项目开发中,为了简化Gradle脚本的维护,我们通常将一些公用的东西抽成全局变量,或者将公共逻辑抽成一个单独的gradle文件,在各个子模块引用这个公共脚本文件,以此实现配置或逻辑的复用。如:

  • 将buildVersion,targetVersion等放到全局变量中,实现统一管理所有模块的目标版本
  • 将androidx等依赖库的版本定义到全局变量,实现统一管理依赖的版本号,避免版本号冲突
  • 将构建产物重命名成公司合规的名称,拷贝构建产物到指定目录等逻辑定义到单独的gradle文件中,避免所有子模块都要开发一遍重复的逻辑

4.1,Gradle中的变量类型

Gradle中可以声明两种类型的变量:局部变量(local),扩展属性(extra)

4.1.1,局部变量

局部变量用def关键字来声明,他只在声明他的地方可见,局部变量是Grovvy中的一个基本特性。
局部变量可见域如下:

  • 如果局部变量定义在Task中,则在Task中可见,Task外部无法访问
  • 如果局部变量定义在function中,则在function中可见,function外无法访问
  • 如果局部变量定义在build.gradle文件中,则在整个gradle文件中可见,此脚本中的task均可访问此变量,但此脚本中的function无法访问

4.1.2,扩展属性

扩展属性允许将属性添加到现有的域对象中,所有的已知扩展有一个统一的类型ext,支持扩展属性的对象有projects,tasks,configurations,dependencies等。可以在运行时使用其他对象的扩展属性。属性扩展对象支持groovy属性语法,可以通过.操作符直接读取。

 
  1. ext {
  2. var1 = "ext value1"
  3. }
  4. println project.ext["var1"]
  5. println project.ext.get("var1")
  6. println project.ext.var1
  7. println project.var1

以上方式均可正常访问扩展属性变量。

4.2,全局变量

由于rootProject可以很方便在各个build.gradle脚本文件中获取到,结合前文说到的扩展属性,我们可以在项目级别的build.gradle文件中定义扩展属性,来实现全局均可访问的全局变量能力。

除此者外,我们还可以在项目级别的gradle.properties文件中定义值,也可实现全局访问的全局变量能力。

其次,也可以通过命令行中设置环境变量或者传递参数来实现,这通常在流水线构建时很有用。

4.3,Gradle引用

通常我们会将一些通用的逻辑单独写在一个gradle脚本中,然后在要使用的地方applay,即可实现脚本复用。比如maven上传脚本,代码检查监本,代码样式脚本等。

 
  1. apply from: rootProject.file("path of xxx.gradle file")

5,Gradle插件

前文说到Gradle是一个扩展起来非常方便的一个构建脚本语言,扩展Gradle原有功能的常见手段就是自定义Gradle插件。Gradle插件简单概括就是把构建逻辑可复用的部分打包起来,应用到不同的项目构建中。

上文提到的Gradle应用就是Gradle插件的最简单的一种实现方式。除此之外,还可以在项目根目录新建buildSrc目录(注意这个目录名是限定死的,不能改成别的),Gradle会自动识别这个目录下的代码是插件代码。或者新建一个java项目,然后发布产物到maven,其他项目通过apply plugin的方式使用插件

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有马大树

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值