Gradle可能会让人感到困惑和难以理解。当你创建一个新的Android项目时,系统会生成一些Gradle文件就不管了。开发者经常会从GitHub或Stack Overflow上复制粘贴代码,而并不真正理解其中的原理。
本系列将解释Gradle构建中常见代码的含义,并作为你将来可以参考的速查表。除了这篇文章外,我还创建了一个GitHub Gist,其中涵盖了典型的Gradle项目设置,并包含一个markdown速查表。如果你想跟随一个现有项目学习,我推荐使用这个多平台compose模板或KaMP Kit,它是KMM项目的一个很好的起点。
在本文中,我们将探讨Gradle如何工作,深入了解Gradle插件,并为你留下一些方便的速查卡片以供参考。
Gradle构建实际发生了什么
在我们开始讨论插件之前,让我们先了解构建过程中发生的事情:
- 根据
gradle-wrapper.properties
下载Gradle包装器 - 构建检测
settings.gradle
文件并进行评估,以确定哪些项目参与 - 为每个项目创建项目实例,并评估它们的
build.gradle
脚本 - 为请求的任务创建任务图
- 按照依赖关系的顺序安排和执行每个选定的任务
这里需要注意的主要是构建运行的顺序。它首先检查settings.gradle
,然后遍历settings中定义的每个子模块,并运行它们的build.gradle
文件。然后如前所述,按照依赖关系的顺序执行任务。实际顺序可能很复杂,但简单来说,以KMP为例,我们可以说:
settings.gradle
运行每个子模块的build.gradle
settings.gradle
或build.gradle
解析插件build.gradle
检查要运行的代码块(如android
和kotlin
)并运行它们
- 这些代码块解析
dependencies
我喜欢这样思考这个顺序:
settings.gradle
-> build.gradle
-> plugins
-> blocks
-> dependencies
因此,考虑到这一点,我们将首先介绍插件,然后是常见的kotlin
和android
代码块,接着是依赖项,最后回到一些关于settings.gradle
的说明。Gradle来源
Gradle脚本文件可以根据所选的DSL有两种不同的扩展名:.gradle
用于Groovy DSL,.gradle.kts
用于Kotlin DSL。本博文中这两个扩展名可以互换使用,因为它讨论的是Gradle的概念而不是语法。
在Gradle中,有很多方法可以做同一件事。这篇文章不一定会讨论位置的最佳实践,但会给出一些关于如何在多模块项目中组织定义的建议。
这不仅是给你的速查表,也是给我的。我仍在学习,所以如果我有没有涵盖的内容,或者有不正确的内容,请告诉我。
定义
在我们开始之前,这里有一些我在文章中使用的可能不清楚的术语:
Level
:在本文中,当我说"level"时,我指的是模块层级。例如,root或top level指的是根目录的build.gradle
和模块。DSL
:领域特定语言。例如:Kotlin DSL,Plugins DSL,Gradle DSL
插件概述
插件DSL
传统插件应用方式
什么是插件
插件为你的Gradle构建添加功能。它们为项目添加新的任务、域对象和特性。更多信息在这里
示例:添加kotlin("multiplatform")
允许你添加包含sourcesets和targets的kotlin代码块,并添加诸如build iosArm64Binaries
之类的任务
如何添加插件?
向模块添加插件
让我们从顶层开始,从模块的build.gradle
开始。首先,我们添加插件。
插件在plugins
代码块中添加,可以添加到build.gradle
或settings.gradle
中的pluginManagement
代码块中(我们稍后会讲到)。子模块继承插件,所以如果你想在子模块之间共享插件,可以在根模块中定义。
有两种方式包含插件:
id("id")
:通过id导入插件,传入插件的组ID和名称kotlin("id")
:Kotlin是一个简便的写法,表示我们使用"org.jetbrains.kotlin"
组ID。这相当于调用id("org.jetbrains.kotlin.id")
Version:你必须在项目中为插件添加版本。如果你与子模块共享插件,可以在根模块中定义版本,否则在使用的模块中设置版本。版本会被子模块继承,但如果需要,你也可以在子模块中覆盖版本。
Apply:你可以使用apply选择是否应用插件。这在你想在根项目中全局定义插件,但不想在根模块中实际使用它的情况下很有用。声明此插件的子模块将自动应用它。
KMP注意事项:在模块中定义的插件会应用到所有sourcesets。例如,如果你包含了id("org.jetbrains.kotlin.id")
插件,它会尝试将该插件应用到你的iosMain
sourceset并导致错误。
管理插件
其次,我们定义它来自哪里。
你需要定义插件来自哪里,否则Gradle不知道你在说什么。默认情况下,Gradle在gradlePluginPortal检查插件。如果你使用的插件在另一个仓库中,你可以在pluginManagement
代码块中定义它。pluginManagement
代码块是你设置插件来源仓库的地方。此外,你也可以在这里设置插件,使用上面提到的相同语法。我们将在未来的文章中讨论maven,但现在只需要知道mavenCentral
是一个用于插件和依赖项的流行仓库。
传统方式
传统方式有点不同。我们使用buildScript
而不是pluginManagement
。Repositories
是相同的,但注意这个版本中有一个Repositories
代码块。这是你定义classpaths的地方,它们是插件的依赖项。
个人建议
定义插件有很多不同的方式,但截至2023年5月,这是我的建议:
- 遵循android指南
- 在
settings.gradle
中使用pluginManagement
定义所有插件信息,包括版本,但设置apply为false - 然后在子模块中包含插件,但不包含版本
速查卡片
这里是一些关于Gradle插件的快速参考代码
代码块
plugins
:定义你想使用的插件的地方(更多信息)repositories
:告诉Gradle在哪里查找项目的代码块(更多信息)pluginManagement
:定义项目插件的地方,包含plugins
和repositories
代码块(更多信息)BuildScript
:(插件的传统方式)定义添加插件的repositories
和dependencies。也可以用来添加在项目中使用的变量,如版本(更多信息)
插件
id("id")
:用组ID和名称添加插件(例如:"com.android.library"
)(更多信息)kotlin("id")
:Kotlin表示我们使用"org.jetbrains.kotlin"
组IDversion("version")
:设置插件版本,在某个模块层级是必需的(更多信息)apply(boolean)
:是否应用插件。如果你想在根模块中定义插件,但只在某些特定子模块中使用它,这很有用(更多信息)
传统方式
classpath
:你想添加的插件的依赖,classpath
在buildscript
代码块中使用apply("id")
:添加插件的传统方式
仓库
gradlePluginPortal()
:默认Gradle插件门户(https://plugins.gradle.org/)。如果没有为插件定义仓库,Gradle将默认使用这个(更多信息)mavenCentral()
:中央Maven仓库(https://repo1.maven.org/maven2/)(更多信息)