1. 前言
作为一个Android程序员,Gradle真是最熟悉的陌生人,每天使用又知之甚少,可能连一知半解都谈不上,Gradle的概念都不能很完整的表达出来,聊几句Gradle,不外乎是:构建工具,基于Groovy语言,使用groovy dsl 编写脚本。真的很难懂哦,今天就扒一扒Gradle的面纱。没有实际操作,api如何使用,大部分是概念解析。
Gradle是非常复杂的,概念,流程,生命周期,api,编写脚本 要理解的内容真的很多。独立插件又是一大波知识点。
从零开始对Gradle没有任何概念的同学,要付出一些精力和时间,不是短时间就能理解掌握的。
2.官网的第一句介绍
虽然Gradle官网有中文站点,访问速度很快 但是没有中文版本,大家可以利用浏览器的翻译功能,翻译不好的地儿就开两个网页中英文对照看(大佬当我没说)
Gradle is an open-source build automation tool focused on flexibility and performance. Gradle build scripts are written using a Groovy or Kotlin DSL.
Gradle是一个开源构建自动化工具,专注于灵活性和性能。Gradle 构建脚本是使用 Groovy 或 KotlinDSL 编写的。
Gradle用户指南的第一句话,可知
-
Gradle是一个构建工具
-
Gradle的构建脚本使用 groovy 或 kotlin DSL编写
-
Gradle的构建脚本 并不是Gradle本身 使用 groovy 或 kotlin DSL编写
-
groovy 或 kotlin DSL 想要表达的意思是
- groovy DSL
- kotlin DSL
-
先不说 groovy ,kotlin 作为Android程序员可太熟了, 可kotlin DSL是个啥玩意
-
能够得出的结论是:
Gradle 并不是一门语言 是构建工具, Gradle使用了groovy 语言 或 kotlin 语言 用来编写Gradle 的构建脚本。
有三个概念
- gradle 本身
- gradle的脚本
- 脚本使用的语言:groovy 或 kotlin
3.Gradle是什么
3.1 构建工具
Gradle并不是一门语言,是构建工具。
Gradle也是一个软件程序,这个程序的作用是帮助程序员构建软件。
嗯,构建其他软件是什么意思??
在Android中,使用gradle构建项目,帮助程序员下载依赖,编译程序员内的资源,生成apk包
web前端使用npm构建项目,同样下载依赖,编码完成后打包
简单的说:构建工具用来下载依赖,项目打包的。使程序员能够专心的写业务代码,避免被项目配置,打包流程这种麻烦繁琐的事情占用过多的精力。
回忆一下最初学Java
使用javac 编译源码 生成class文件,使用命令生成jar包 打JAR包那些事 - 掘金 (juejin.cn)
使用eclipse写SSH,需要手动引入一堆的jar包,项目才能运行。
在开发前,程序员自己下载开发需要的三方jar包。开发后,程序员自己使用命令编译源码,生成可执行文件。
虽然java,Android官方肯定提供了许多工具帮助开发者完成打包过程。但是太麻烦太麻烦了,通过引入构建工具,构建工具把原本的打包过程细分未一个一个步骤,逐步实现。
程序员提供代码,图片,视频等程序资源提供给构建工具,工具还程序员一个能够运行的软件包。
3.2 能够构建任何软件
Gradle作为一个构建工具,它真正优秀和强大的地方在于,它并不是只能服务于某一门语言或平台的工具软件。
它是通用的构建工具,能够构建任何项目,比如:Android,c++,java,kotlin,spring,swift等等。
它为什么这么牛呢?
Gradle抽象一套软件构建的逻辑,它并不承担任何实际工作。Gradle没有面面俱到将所有语言的构建流程都实现一遍,它抽象出三个构建阶段:初始化,配置,执行。
同时提供插件 功能,当使用Gradle构建Android项目,集成Android插件。打包java项目就集成Java插件。
用程序员行话来解释Gradle,它是面向对象的设计思路,使用抽象类抽象出三个方法:init,configure,execute。
为了实现某一门语言的构建工作,继承抽象类,各自按照平台特性实现方法,比如:
抽象类 BasePlugin
子类:AndroidPlugin,javaPlugin,kotlinPlugin等等
所以Android 和 Gradle 是没有任何联系的两个东西,Google官方开发出基于Gradle的构建插件才把Android和Gradle 联系起来,也就是大家熟悉的AGP
AndroidStudio是Google官方的定制idea,天生的就把Gradle和Android结合起来,不需要程序员二次配置,这也是为什么在Android中会决定Gradle和Android紧密的想一个东西的原因
总结:
Gradle是一个构建工具同时又想一个开源框架,抽象出一套通用的构建流程,允许开发者自行实现构建任务,从而达到能够构建任何项目的效果。
4.第一个Gradle项目
作为Android程序员与Gradle打交道,往往是使用AndroidSutdio的时候,难免对Gradle的理解与Android项目联系在一起。
我们看看如何创建一个Gradle项目,增强对Gradle的认识。
4.1 环境配置
-
需要java环境,Java8以上 ,使用
java -version检查Java版本 -
下载Gradle Gradle | Releases
- 有两个下载选项,binary-only 是只包含核心类库的版本 complete 是包含文档,源码的版本
- 下载完成后,解压的任意目录,添加bin目录的环境变量即可:D:\xxx\gradle-7.4.2\bin
- 配置完成后,使用命令
gradle -v输出版本号 配置成功
4.2 创建Gradle项目
创建Gradle项目非常简单 在任意目录下使用命令 gradle init ,命令行程序有步骤提示,引导开发者,如下所示,创建一个基础项目
D:\document\gradle\demo\demo>gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 1
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
Project name (default: demo):
> Task :init
Get more help with your project: Learn more about Gradle by exploring our samples at <https://docs.gradle.org/7.4.2/samples>
BUILD SUCCESSFUL in 11s
2 actionable tasks: 2 executed
生成的目录结构如下所示,是不是很眼熟了,这就是Gradle项目最初的摸样
再来构建一个Java项目,也可以构建c++,groovy,kotlin项目
D:\document\gradle\demo\javaDemo>gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 2
Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6] 3
Split functionality across multiple subprojects?:
1: no - only one application project
2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2]
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 1
Project name (default: javaDemo):
Source package (default: javaDemo):
> Task :init
Get more help with your project: <https://docs.gradle.org/7.4.2/samples/sample_building_java_applications.html>
BUILD SUCCESSFUL in 27s
2 actionable tasks: 2 executed
生成目录如下,多了app目录,app目录下是java src 目录和 build.gradle文件。
在当前目录下使用命令 ./gradlew run 运行项目,通过命令行可以看到Gradle项目的编译过程,下载依赖最终运行java项目 输出 Hello world!
4.3 项目结构介绍
settings.gradle 文件: 用于确定哪些模块参与构建;
根目录下 build.gradle 文件: 用于定义所有子模块公共的配置参数;
模块下 build.gradle 文件: 用于定义子模块的配置参数,它可以覆盖项目级 build.gradle 文件中定义的配置;
gradle/warpper: 负责自动下载安装项目所需的 Gradle 环境的脚本;
**gradlew :**Linux下Gradle任务执行脚本
**gradlew.bat :**Windows下Gradle任务执行脚本
gradle.properties: 用作项目级 Gradle 配置项,会覆盖全局的配置项;
local.properties: 用作项目的私有属性配置,例如 SDK 安装目录,一般不把 local.properties 加入版本控制。
4.4 小结
经过实际操作,小小的上手一下 是不是对Gradle有更深的理解了。
Gradle作为构建工具的同时,又可以说是一款开源框架,它只定义了编译流程,不限定具体执行什么任务,编译什么语言。
Gradle是单独的一个应用程序,与我们编写的代码是两个东西,只在构建项目时起作用。
5. Gradle—Java项目
之前提到过,Gradle也是一个应用程序,它是纯Java编写的,一个正宗的运行在JVM上的java项目。
???Gradle不是使用groovy语言么,怎么又变成Java编写的了。
Gradle的脚本 settings.gradle , build.gradle 是使用groovy语言,是程序员使用groovy或kotlin 写给Gradle程序看的。
但是Gradle本身是用Java编写的。
打开刚刚下载的Gradle目录 可以看到bin目录,lib目录,如果下载的是包含源码的版本还可以看到src目录,在 gradle-7.4.2\src\bootstrap\org\gradle\launcher 能够找到Gradle的启动类,都是正宗的java代码
public class GradleMain {
public static void main(String[] args) throws Exception {
String javaVersion = System.getProperty("java.specification.version");
if (javaVersion.equals("1.6") || javaVersion.equals("1.7")) {
String gradleVersion = GradleVersionNumberLoader.loadGradleVersionNumber();
System.err.printf("%s %s requires Java 1.8 or later to run. You are currently using Java %s.%n", "Gradle", gradleVersion, javaVersion);
System.exit(1);
}
Class<?> mainClass = Class.forName("org.gradle.launcher.bootstrap.ProcessBootstrap");
Method mainMethod = mainClass.getMethod("run", String.class, String[].class);
mainMethod.invoke(null, "org.gradle.launcher.Main", args);
}
}
那么Gradle程序的运行机制是什么呢?
它并不像平常的Java程序,启动一次进程就消失了,下次运行开启的是一个全新的进程。
别的语言程序是Gradle是个啥情况我不太清楚,对于Android来说构建项目是个很频繁的过程,如果每次都新开启一个构建进程,是个很耗时的情况。
第一次构建项目 和 之后构建项目的耗时体验还是差距很大的。
为此Gradle设计了三个进程配合完成构建任务
- client 进程
- wrapper 进程
- Deamon 进程
client进程非常轻量,正如它的名字一样,它是客户端进程每次构建项目的时候都会创建一个新的,作用是发起进程间通信,向Deamon进程发送任务,Deamon进程是负责干活的进程
Deamon进程第一次启动后常驻后台,不依赖 AS 而是独立存在,是一个守护进程一段时间内没有使用会自动关闭(据说是三小时)
Deamon进程会在内存中缓存项目结构,文件,任务等的信息。
通过命令 gradle --status 可以查看已经启动的deamon进程,因为配置gradle是最新的7.4.2,所以只会展示当前版本的deamon进程,
但实际上 使用不同版本的gradle时会启动对应版本的gradle,比如:运行了两个项目,7.0和6.0 那么系统中就会存在 两个deamon进程,这也是Gradle占用内存的一个原因,可以通过设置本地统一gradle版本进行优化
在上一节使用命令 gradle init 创建项目的时候 第一次运行的时候 看到命令行 会有关于Deamon进程启动的信息展示,之后在运行就没有了
wrapper进程唯一的 作用是下载Gradle版本,每个Gradle项目中都有一个Gradle目录。构建时client 进程发现所需版本的 Gradle 本机没有,那么就会启动 wrapper 进程,根据 gradle.properties 里面的参数去 运行 gradle-wrapper.jar 里面的下载程序去下载 Gradle 文件
6. 关于DSL
在学习Gradle时 经常会听到 “用 groovy DSL编写 gradle脚本”,kotlin火了之后 又会听到 “用kotlin DSL编写gradle脚本”
groovy我不认识,据说也是运行在Java虚拟机上的语言 和Java无缝衔接,但是从来没用过 不好评论。 DSL 就更别提了 见识短浅的我 如果不是学习gradle 压根就没听过 DSL的概念,特定领域语言
什么东西?
问题已经有了 怎么解决呢? groovy我不认识,dsl 没听过。 可kotlin我认识啊,官方推荐语言每天使用, 可 kotlin dsl 也没听过啊, 从熟悉的东西入手,先了解一下kotlin dsl。
6.1 DSL分析
DSL domain-specific language 领域专用语言,关于DSL的概念就不详细说了,感觉说了也没啥用更容易引起歧义,不好理解。
DSL语言分两种
外部 DSL:
从零开始构建的语言,需要实现语法分析器等,不依赖某一门通用的编程语言,比如:HTML、CSS、SQL
内部 DSL:
需要依赖某一门通用的编程语言,这个语言被称为宿主语言,比如:kotlin,groovy
先分析下外部DSL
sql ,html ,css,无论哪一端的开发者多多少少应该都用过,它们与java,kotlin,swift这种通用语言相比有什么区别呢? 用查询举例,
sql是只能使用数据库操作的语言,Java同样也可以用文件存取数据。
模拟一个场景,普通文件存储100条数据,数据库存储100条数据,把数据取出输出的控制台。
Java想要实现这个功能需要程序员做很多事情,文件流操作,数据转换,循环遍历等等
而SQL,它天生就是为了数据库存取操作而生的。 使用 select语句 就能所有的数据查询出来。
Java 和 sql 差不多的需求,但是需要开发者实际编写的代码数量差距非常大。
为什么会这样?
SQL 是 DSL, 针对于数据库操作领域专门设计的语言,因为SQL面对的问题少,它只需要考虑几种特殊的场景,所以它可以对这些场景进程高度的封装。
假设 数据的操作就是 CURD,就这四个固定场景,那么设计者就可以尽情的对CURD 进行封装,用起来越简单越好,压根就没有别的使用场景,不用考虑灵活 扩展
Java不同,它是通用语言,要做的事情和能做的事情都非常多,有过设计组件经验的同学应该有体会,灵活意味使用起来会麻烦。
SQL看似简单,但是底层做了非常多的事情,SQL有专门的解释器,其实就是逻辑处理,Java要写的文件流,循环遍历,sql一样少不了,只是SQL针对于单一场景封装优化的更好。
HTML,css也是同理,存在对应的解释器,解释器替开发者做了绝大部分工作,所以才可以一个标签就可以出效果。
外部DSL总结
因为dsl 语言专门只需要考虑特定场景,设计者可以极致的封装,使代码编写简单,达到 一条语句 完成 一大块通用语言 才能实现的效果
DSL的特点是,编码时 代码看起来像 语句 或 关键字构成的,比如 select * from tb_user
6.2 kotlin DSL
外部DSL 是一种全新的语言,内部DSL一门通用语言特性而实现的,再官网找到一篇关于DSL的文,
类型安全的构建器 - Kotlin 语言中文站 (kotlincn.net) 通过使用命名得当的函数作为构建器,结合带有接收者的函数字面值,可以在 Kotlin 中创建类型安全、静态类型的构建器。 类型安全的构建器可以创建基于 Kotlin 的适用于采用半声明方式构建复杂层次数据结构领域专用语言(DSL)
官方描述关键点:
”使用命名得当的函数“
“类型安全、静态类型的构建器”
“适用于采用半声明方式构建复杂层次数据结构”
参考官方写个简单的测试用例
class ExampleUnitTest {
//代码调用
@Test
fun test() {
val result = html {
title = "我是title"
body = "我是body"
}
println("结果:${result.title} -- ${result.body}")
}
}
//定义数据类
class HTML {
var title: String = ""
var body: String = ""
}
//定义高阶函数 当作构造方法
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
---输出结果
结果:我是title -- 我是body
BUILD SUCCESSFUL in 2s
//调用
html {
// ……
}
//原理
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
是不是有点那意思了,代码非常简单, 看起来像是写了一个 名为html的代码块,实际效果是创建了一个HTML对象
内部原理是kotlin的高阶函数 和 扩展函数,html函数接收了 名为init的 HTML扩展函数,因为扩展函数的特性,作为参数存在的init()函数可以被HTML实例调用
HTML对象的构造过程仍然存在 ,仍然需要new对象,只不过细节被语法特性屏蔽了。
小总结:
kotlin dsl 作为内部dsl,是基于kotlin函数的语言特性实现的
kotlin官方并没有提供如 select,update语句 一样的官方 dsl,只是提供了一种机制 让开发者自行处理,感觉dsl 是另一种封装方式,本质上是方法调用 与 sql,html等 dsl语言相比还是有不小的差距,毕竟目前看来kotlin dsl 的使用方式 就是 关键字+代码块 如:html {}
官方文档的标题 类型安全的构建器 还是很贴切的
6.3 Groovy DSL
看一个非常经典的 Android library 的 build.gradle 脚本,省略部分代码
plugins {
id 'com.android.library'
}
android {
compileSdk 32
defaultConfig {
minSdk 23
targetSdk 32
versionCode 1
versionName "1.0"
}
}
dependencies {
api 'com.squareup.retrofit2:retrofit:2.9.0'
}
上述代码可以分为三大块:
-
plugins
- 对应
org.gradle.plugin.use.PluginDependenciesSpec是Gradle提供的接口,id 'xxx'是接口提供的抽象方法
public interface PluginDependenciesSpec { PluginDependencySpec id(String var1); } - 对应
-
dependencies
- 位于
org.gradle.api.Project接口中,是一个抽象方法,参数是 groovy的 Closure 对象 - Closure 可以理解为 Java中的 lambda表达式,函数接口 和 kotlin中的高阶函数,允许方法传递一段代码块
public interface Project { //...省略 void dependencies(Closure var1); //...省略 } - 位于
-
android
- 是个扩展属性,Google提供的
com.android.tools.build:gradle:xxx插件中实现,并不是Gradle原生的东西 - 原理是利用Gradle的
org.gradle.api.Project接口提供的getExtensions()方法,设置扩展属性。 - gradle扩展 可以理解为 另类的xml配置,作用在于收集数据。xml解析后用JavaBean接收数据,gradle扩展也是同样
//模拟大概代码如下: //针对 当前project 创建扩展属性 project.getExtensions().create("demoUser", UserExtension.class); //UserExtension 相当于javaBean 承载数据 public class UserExtension { private String name; private int age; //getter setter省略 } //在gradle脚本中使用 demoUser{ name = "xixixi" age = 12 } - 是个扩展属性,Google提供的
上述的Gradle的接口文件,方法定义是Gradle使用Java编写的,Google提供的Android插件早些版本是用Java编写,最近几个版本用kotlin编写
因为Gradle脚本使用 groovy语言,它的语法糖省略了一些在Java 或 kotlin中调用函数的必要内容,build.gradle不省略语法的写法如下:
plugins代码块下的 id实际上是参数为String的接口抽象方法,正常的方法调用 与Java一致,id('com.android.library')不省略括号android代码块 是Google插件提供的功能,实际上是扩展属性的赋值,不省略复制等号dependencies代码块,是project接口的抽象方法,参数是groovy的 Closure 对象,相当于lambda表达式,高阶函数。 本质上dependencies是一次方法调用不省略 参数括号
经过编译是可以运行的
plugins {
id('com.android.library')
}
android {
compileSdk = 32
defaultConfig {
minSdk = 23
targetSdk = 32
versionCode = 1
versionName = "1.0"
}
}
dependencies ({
api 'com.squareup.retrofit2:retrofit:2.9.0'
})
小总结:
groovy DSL 比kotlin DSL要更复杂一点,语法规则上有函数的省略,Closure 闭包,官方提供的dsl等等机制,学习起来有一定难度。
如果不熟悉groovy 的语法,没有实际使用过 只看看api介绍 很难对groovy这么语言形成概念。
groovy的语法省略太多,对于熟悉groovy的人来说确实很棒,但是对于新手真是麻了,学习成本太高了。
比如:
plugins代码下的 id com.android.library 与 Android 代码块下的 compileSdk 32 ,对于没有研究过groovy的人来说,谁能想到一个是方法调用,一个是赋值呢。
6.4 DSL参考与总结
Android Gradle plugin API reference | Android Developers (google.cn)
类型安全的构建器 - Kotlin 语言中文站 (kotlincn.net)
干货 | 实现一个属于你的“语言”-携程Kotlin DSL开发与实践 (qq.com)
Kotlin 修炼手册(15)DSL - 掘金 (juejin.cn)
一杆到底:DSL 领域特定语言-阿里云开发者社区 (aliyun.com)
谈谈 DSL 以及 DSL 的应用(以 CocoaPods 为例) - 知乎 (zhihu.com)
从groovy 的 DSL来看,它的学习过程是非常陡峭的。所以大家千万千万 千千万万不要轻易用 kotlin DSL去设计代码,老老实实写函数就好了,大家一眼就能看明白,千万别炫技。如果用了kotlin dsl设计代码 请留下足够丰富的文档,让后来人能看懂。
对于DSL本身,我感觉是一种在特定场景下的高度封装,好处是使用真的简单,坏处就是如果文档不丰富真的难懂。
在如SQL,HTML等 独立的DSL语言中,一个语句,标签或关键字 就能达到明显效果的原因在于有专属的词法分析,解析器等组件在背后工作。
groovy,kotlin等 内部DSL中,一个简洁的语句 或 代码块的背后有 语言特性 或 存在对应的类在背后执行逻辑。这些干活的类可能是官方定义的,也可以是配合 Gradle插件机制 由程序员自定义的。
7. Gradle脚本
Gradle常见的脚本有两个 settings.gradle build.gradle ,还有一个不常见的 init.gradle
Gradle脚本使用groovy语言,groovy 也是一种JVM语言,能够和Java无缝衔接。上述脚本在Gradle运行时 会被编译为class文件,生成对象Java虚拟机中运行。之前也提过Gradle 就是个Java程序
打印一下类信息
熟悉的 getClass(),所有反射的api都能调用。熟悉的堆栈打印方式 new Throwable().printStackTrace() 。 一切都很像Java,但是整体看Gradle脚本就一点都不像Java
//settings.gradle中输出日志
println("setting class -------- ${this.getClass()}")
println("setting Superclass -------- ${this.getClass().getSuperclass()}")
println("gradle class -------- ${gradle.getClass()}")
println("gradle class -------- ${gradle.getClass().getSuperclass()}")
setting class -------- class settings_aj0eixozohtkc94mwkss4h8rf
setting Superclass -------- class org.gradle.initialization.SettingsScript
gradle class -------- class org.gradle.invocation.DefaultGradle_Decorated
gradle class -------- class org.gradle.invocation.DefaultGradle
//build.gradle中输出日志
println("project class -------- ${project.getClass()}")
println("project Superclass-------- ${project.getClass().getSuperclass()}")
project class -------- class org.gradle.api.internal.project.DefaultProject_Decorated
project Superclass-------- class org.gradle.api.internal.project.DefaultProject
//还可以打印堆栈信息 查看调用顺序
new Throwable().printStackTrace()
在Java中编写一个类是有明确语法的,必须声明Class,所有代码写在Class代码块中,代码一板一眼必须按照规则编写,随便写是不行的编译不通过。
脚本是没有硬性的规则,可以直接写代码。脚本执行时,脚本解析器按顺序从第一行逐行执行。
所以Gradle脚本可以看作一个另类的Java文件
- 默认导入很多类,不需要导包
- 默认实现了某些接口 或 抽象类的文件,可以直接调用 接口暴露的方法
- 由于是脚本文件,可以直接写代码,定义变量,方法,没有绝对语法编写规则
- groovy的语言特性,有很多简写的语法糖
比如:
settings.gradle 默认实现好了 org.gradle.api.initialization.Settings 接口,可以直接调用接口定义的方法。最常用的 include ':app' ,实际上就是个方法调用 void include(String... var1);
但由于语法特性 方法调用和Java看起来又完全不同。
settings.gradle 如果按照Java的写法可能会是。 但用于Gradle脚本的特性,一个空脚本就已经默认继承类了,可以调用方法,随意编码。
public class DemoSetting implements Setting{
public DemoSetting() {
include("app");
}
@Override
public void include(String name) {
// 一堆实现代码
}
}
小总结:
- gradle脚本理解成一个有很多语法省略的特殊Java类
- 代码没有严格编写规则,可以随意定义
- 每个脚本已经默认继承了接口或抽象类,把它当成一个Java类吧 ,大胆的调用接口暴露方法
- 难点在于不知道接口暴露了什么方法,有啥参数,emm 决解办法就是下载个源码看看
init.gradle 对应 org.gradle.api.invocation.Gradle接口
settings.gradle 对应 org.gradle.api.initialization.Settings 接口
build.gradle 对应 org.gradle.api.Project 接口
原理可看视频:你的 Gradle脚本究竟是什么?_哔哩哔哩_bilibili
7.1 init.gradle
没有了解过Gradle的同学应该不知道这个东西,它确实也没啥用,是更大范围的初始化文件。
settings.gradle 和 项目根目录下的 build.gradle 是针对当前项目的通用配置。
init.gradle是针对所有使用了xxx版本Gradle项目的通用配置。
如下截图是当前电脑内,AndroidStudio下载过的所有Gradle版本,每个目录下都有init.d目录,用来存放init.gradle 默认是空的,没有配置文件。如果设置了配置文件,那么当依赖此版本的项目开始构建,就会默认先执行。
由于init.gradle 的范围太大了,一旦配置所有项目都受影响,几乎是用不到。
8. Gradle构建生命周期
Gradle构建分为三个过程:初始化,配置,执行
8.1 初始化阶段
执行 init.gradle 脚本,生成 Gradle对象
执行 setting.gradle 脚本,生成 Setting对象,执行include函数,确定有哪些项目会参与构建,每个项目会对应生成一个Project对象,最终形成项目结构
8.2 配置阶段
首先执行根目录的build.gradle 再执行每个项目的 build.gradle 脚本,执行脚本的过程中 没那么神秘 就是 一次执行代码而已。
但代码执行后会有些额外的产物,有依赖关系的任务,任务间彼此依赖,形成一个有向无环图。
这是Gradle的核心,其实Gradle更像一个任务框架。
想要实现Java打包,Android打包时一个复杂,且有一定顺序,规律的巨大任务。大任务又可以解析为一个个小任务。任务之间具有规则和依赖关系。
具体的打包步骤 是实际情况而定,Java打包 和 Android打包肯定不同。 Gradle出色的地方在于,它把打包抽象为一个流程,并提供插件机制,插件如何实现Gradle不管。Java,Android 或是 c++,具体的打包操作自己实现。
插件需要什么配置信息,通过build.gradle 配置。插件读取到配置信息,生成一个个任务,保存在Gradle中的TaskContainer 。
配置过程的最终成果就是生成:当前项目的任务有向无环图
8.3 执行阶段
执行阶段 好像没啥可说的,执行配置阶段生成的任务
配置文件中有哪些常用api ,生命周期回调 可看这两篇:
深度探索 Gradle 自动化构建技术(三、Gradle 核心解密) - 掘金 (juejin.cn)
Gradle 爬坑指南 -- Gradle 核心模型、Hook 函数、ext 扩展属性、Project API - 掘金 (juejin.cn)
9. 总结—偷图
推荐视频
来自Gradle开发团队的Gradle入门教程_哔哩哔哩_bilibili
你的 Gradle脚本究竟是什么?_哔哩哔哩_bilibili
系列文章
补齐Android技能树「Gradle篇」 - coder_pig的专栏 - 掘金 (juejin.cn)
Gradle 爬坑指南 -- 导论 - 掘金 (juejin.cn) 这篇总结了N个资源 ,作者本身也有写解读
深度探索 Gradle 自动化构建技术(一、Gradle 核心配置篇) - 掘金 (juejin.cn)
看完这一系列,彻底搞懂 Gradle - 知乎 (zhihu.com)
为什么说 Gradle 是 Android 进阶绕不去的坎 —— Gradle 系列(1) - 掘金 (juejin.cn)