前面我们深入探讨了 Gradle 生命周期,理解了构建的 “运作机制”。今天,我们要更进一步,学习 Gradle 的 “语言”—— Gradle 基础语法与 DSL。
你可能会觉得 Gradle 文件看起来有点 “神秘”,不像 Java 或 Kotlin 那样 “规规矩矩”。 这是因为 Gradle 构建脚本是使用 Groovy DSL (Domain Specific Language,领域特定语言) 编写的。
Groovy 是一种基于 JVM 的动态语言,而 Gradle DSL 则是 Groovy 的一个 “方言”,专门为构建自动化而设计。
掌握 Gradle 基础语法和 Groovy DSL,就像学习一门新的编程语言,虽然一开始可能会有些陌生,但一旦入门,你就会发现它简洁、强大、灵活,能让你更高效地编写构建脚本,实现各种复杂的构建需求。
Gradle 构建脚本:Groovy DSL 的舞台
首先,我们要明确一点:Gradle 构建脚本 (例如
build.gradle, settings.gradle) 都是用 Groovy DSL 编写的。这意味着,要编写 Gradle 构建脚本,我们就需要了解 Groovy DSL 的基本语法。Groovy DSL 构建在 Groovy 语言之上,它在 Groovy 的基础上,添加了一些专门为构建自动化设计的语法糖和约定,让构建脚本更简洁、更易读。但其本质仍然是 Groovy 代码。
Groovy 基础语法速览:Gradle DSL 的基石
虽然 Gradle DSL 在 Groovy 基础上做了简化和定制,但掌握一些 Groovy 基础语法,对于理解 Gradle DSL 仍然至关重要。下面,我们快速浏览一些 Groovy 常用语法元素:
语句和表达式 (Statements and Expressions)
- 语句 (Statements): 执行某些操作的代码单元,例如变量声明、赋值、方法调用等。 语句通常以分号
;结尾 (但 Groovy 中分号是可选的)。
- 表达式 (Expressions): 产生值的代码单元,例如字面量、变量、运算表达式、方法调用 (如果方法返回值) 等。 表达式可以作为语句的一部分,也可以单独存在。
Groovy 中,很多语句也可以作为表达式使用,例如赋值语句:
变量 (Variables)
- 动态类型 (Dynamic Typing): Groovy 是一种动态类型语言,变量声明时不需要显式指定类型,类型在运行时确定。 可以使用
def关键字声明变量。
- 类型可选: 即使不使用
def关键字,也可以声明变量 (但建议使用def增加代码可读性)。
- 变量作用域: Groovy 变量的作用域与其他编程语言类似,有局部变量、成员变量、全局变量等。在 Gradle 构建脚本中,我们通常使用局部变量和
Project对象的属性。
字符串 (Strings)
Groovy 支持多种字符串表示方式:
- 单引号字符串 (
'...'): 最简单的字符串,不支持字符串插值 (String Interpolation)。
- 双引号字符串 (
"..."): 支持 字符串插值 (String Interpolation),可以使用${变量名}或${表达式}在字符串中引用变量或表达式的值。
- GString (Groovy String): 双引号字符串的另一种叫法,强调其支持字符串插值的特性。
- 三单引号字符串 (
'''...'''): 多行字符串,保留字符串中的换行和格式,不支持字符串插值。
- 三双引号字符串 (
"""..."""): 多行字符串,保留字符串中的换行和格式,支持字符串插值。
列表 (Lists)
- 创建列表: 使用方括号
[...]创建列表,元素之间用逗号,分隔。 Groovy 列表可以是异构的,即可以包含不同类型的元素。
- 访问列表元素: 使用索引 (从 0 开始) 访问列表元素。
- 列表常用方法: Groovy 列表提供了很多便捷的方法,例如
add(),remove(),size(),each(),collect(),findAll()等。
Map (Maps)
- 创建 Map: 使用方括号
[:]或as关键字创建 Map,键值对之间用冒号:分隔,键值对之间用逗号,分隔。
- 访问 Map 元素: 使用键名访问 Map 元素,可以使用点号
.或方括号[]访问。
- Map 常用方法: Groovy Map 也提供了很多便捷的方法,例如
put(),remove(),size(),each(),keySet(),values()等。
闭包 (Closures)
闭包 (Closures) 是 Groovy 最重要的特性之一,也是 Gradle DSL 的核心组成部分。 理解闭包对于编写 Gradle 构建脚本至关重要。
- 什么是闭包: 闭包是一段 代码块,可以像对象一样传递和执行。 它可以访问定义它的作用域中的变量 (即使在闭包定义的作用域之外执行)。 你可以把闭包理解为 匿名函数 或 Lambda 表达式。
- 闭包定义: 使用花括号
{}定义闭包。
- 闭包执行: 使用
()或call()方法执行闭包。
- 闭包参数: 闭包可以接收参数,参数定义在
>符号之前。 如果没有显式声明参数,闭包会有一个默认参数it。
- 闭包返回值: 闭包可以返回值,默认返回闭包中最后一条语句的值。 也可以使用
return关键字显式返回值。
- 闭包在 Gradle DSL 中的应用: Gradle DSL 大量使用了闭包来进行配置和任务定义。 例如,
android {},dependencies {},task {}等代码块,实际上都是 接受闭包作为参数的方法调用。 这些闭包被称为 配置闭包 (Configuration Closures) 或 Action 闭包 (Action Closures),用于配置 Gradle 对象或定义 Task 的行为。
方法 (Methods)
- 方法定义: Groovy 方法定义与 Java 类似,但 返回类型是可选的 (Groovy 是动态类型语言)。 可以使用
def关键字定义方法 (推荐)。
- 方法调用: Groovy 方法调用非常灵活,可以省略括号
()(如果不会引起歧义)。
- 方法在 Gradle DSL 中的应用: Gradle DSL 中,很多配置项都是通过 方法调用 来设置的。 例如,
compileSdk 33,implementation 'androidx.core:core-ktx:1.9.0',google(),mavenCentral()等,都是方法调用 (省略了括号)。
注释 (Comments)
Groovy 支持两种注释方式:
- 单行注释: 使用
//开头,注释到行尾。
- 多行注释: 使用
/* ... */包围,可以跨越多行。
Groovy DSL for Gradle:构建自动化的 “专属语言”
理解了 Groovy 基础语法,我们再来看看 Gradle DSL 的特性,以及如何在
build.gradle 文件中使用 Groovy DSL。- DSL (Domain Specific Language): 领域特定语言,是为特定领域设计的编程语言,通常比通用编程语言更简洁、更易读、更易用。Gradle DSL 就是为构建自动化领域设计的 DSL。
- 基于 Groovy: Gradle DSL 构建在 Groovy 语言之上,继承了 Groovy 的动态性、灵活性和简洁性。
- 声明式风格 (Declarative Style): Gradle DSL 倾向于 声明式风格,即 描述 “要什么 (what to do)”,而不是 “怎么做 (how to do)”。例如,在
dependencies {}代码块中,我们声明了项目需要的依赖,而不需要关心 Gradle 如何下载和管理这些依赖。 Gradle 会自动处理这些细节。
- 约定优于配置 (Convention over Configuration): Gradle DSL 遵循 约定优于配置 的原则,提供了一些默认约定,例如默认的源代码目录结构 (
src/main/java,src/main/kotlin),默认的构建产物目录 (build/outputs) 等。我们可以通过配置来覆盖这些约定,但通常情况下,使用默认约定可以简化构建脚本。
- 代码块 (Blocks): Gradle DSL 使用 代码块 (Blocks) 来组织配置和定义构建逻辑。 例如,
plugins {},android {},dependencies {},tasks {}等都是代码块,它们实际上都是 接受闭包作为参数的方法调用。代码块内部可以配置属性、调用方法、定义 Task 等。
常用 Gradle DSL 代码块详解
下面,我们详细讲解
build.gradle 文件中常用的 Gradle DSL 代码块:plugins {}代码块: 用于 声明和应用插件。id 'plugin-id'用于声明插件 ID,version 'plugin-version'用于声明插件版本,apply false/true用于控制是否立即应用插件 (Project-levelbuild.gradle通常使用apply false,Module-levelbuild.gradle通常使用apply true或省略apply)。
android {}代码块: 由 Android Gradle 插件提供,用于 配置 Android 构建。 可以在android {}代码块中配置compileSdk,defaultConfig {},buildTypes {},productFlavors {},signingConfigs {},compileOptions {},kotlinOptions {},buildFeatures {},sourceSets {},packagingOptions {},lint {}等 Android 构建相关的配置。
dependencies {}代码块: 用于 声明项目依赖。 可以在dependencies {}代码块中使用implementation,api,compileOnly,runtimeOnly,testImplementation,androidTestImplementation,kapt,annotationProcessor等依赖声明关键字,声明对远程仓库依赖、本地库依赖、模块依赖等。
repositories {}代码块: 用于 配置依赖仓库。 可以在repositories {}代码块中使用google(),mavenCentral(),gradlePluginPortal(),maven { url 'repo-url' },flatDir { dirs 'libs' }等仓库声明关键字,配置 Maven 仓库、Google Maven 仓库、Gradle 插件仓库、本地仓库等。
tasks {}代码块 (或tasks.register(...)) : 用于 定义和配置 Task。 可以使用tasks.register('taskName') { ... }或task taskName { ... }(旧语法,不推荐) 来注册 Task,并在代码块中配置 Task 的属性和行为。 可以使用doFirst {}和doLast {}代码块来定义 Task 的执行逻辑 (Action)。
属性和方法 (Properties and Methods)
在 Gradle DSL 中,我们可以通过 属性 (Properties) 和 方法 (Methods) 来配置和访问 Gradle 对象。
- 属性 (Properties): Gradle 对象暴露的配置项,可以直接赋值或读取。 例如,
android.compileSdk = 33,defaultConfig.applicationId = "com.example.myapp",buildTypes.release.minifyEnabled = true等。
- 方法 (Methods): Gradle 对象提供的方法,可以执行某些操作或返回某些值。 例如,
getDefaultProguardFile('proguard-android-optimize.txt'),repositories.google(),dependencies.implementation(...),tasks.register(...),doFirst { ... },doLast { ... }等。
- 链式调用 (Chaining): Gradle DSL 支持链式调用,可以连续调用多个方法或访问多个属性,使代码更简洁。 例如,
android.defaultConfig.proguardFiles(...)。
- 动态方法 (Dynamic Methods): 由于 Groovy 的动态性,Gradle DSL 允许动态地调用一些方法,例如 Android Gradle 插件提供的
buildTypes.<buildType> {},productFlavors.<flavorName> {}等。 这些方法实际上是动态生成的,用于配置不同的 Build Type 和 Product Flavor。
访问 Project 属性
在 Gradle 构建脚本中,我们可以通过
project 对象访问当前 Project 的属性和方法。 常用的 Project 属性和方法包括:project.name: 获取项目名称。
project.version: 获取项目版本号 (通常在gradle.properties中定义)。
project.group: 获取项目 Group ID (通常在gradle.properties中定义)。
project.buildDir: 获取构建输出目录 (build目录)。
project.rootDir: 获取项目根目录。
project.file(...),project.files(...),project.fileTree(...): 用于创建File,FileCollection,FileTree对象,方便操作文件和目录。
project.property(...): 获取在gradle.properties文件或命令行中定义的项目属性。
project.tasks: 访问项目中的所有 Task。
示例:
Gradle Kotlin DSL (build.gradle.kts):类型安全的 “新选择”
虽然 Groovy DSL 是 Gradle 的 “传统语言”,但 Gradle 也提供了 Kotlin DSL 作为替代选择。 Kotlin DSL 使用 Kotlin 语言编写构建脚本,文件后缀为
.gradle.kts。Kotlin DSL 的优势:
- 类型安全 (Type Safety): Kotlin 是一种静态类型语言,Kotlin DSL 构建脚本具有类型安全,可以在编译时发现类型错误,提高代码质量和可靠性。
- 更好的 IDE 支持: Kotlin DSL 可以享受 Kotlin 语言强大的 IDE 支持,例如代码自动完成、代码导航、重构、错误检查等,提高开发效率。
- 更强的可读性和维护性: Kotlin DSL 语法更严谨、更结构化,代码可读性和维护性更高,尤其是在大型项目中。
- 与 Android 开发语言一致: 如果你的 Android 项目主要使用 Kotlin 语言开发,使用 Kotlin DSL 可以保持技术栈的一致性。
Kotlin DSL 示例 (build.gradle.kts):
选择 Groovy DSL 还是 Kotlin DSL?
- Groovy DSL: 成熟稳定,社区资源丰富,学习曲线相对平缓,对于小型项目或快速原型开发可能更方便。
- Kotlin DSL: 类型安全,IDE 支持更好,可读性和维护性更高,更适合大型项目和长期维护的项目,是 Gradle 官方推荐的未来方向。
最后:
- 掌握 Gradle 基础语法和 Groovy DSL,是成为 Gradle 高手的必经之路。
- 通过学习 Groovy 基础语法,理解 Gradle DSL 的特性和常用代码块,就能编写出更简洁、更强大、更灵活的 Gradle 构建脚本,更好地掌控 Android 构建流程。
- 在未来的博客中,我也会继续分享更多关于 Gradle DSL 的进阶用法和最佳实践,希望能与大家共同进步!
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/546295ab-0793-412f-80fa-7e420e96a6e2
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts