Android Studio 构建系统以 Gradle 为基础,并且 Android Gradle 插件 (AGP) 添加了几项专用于构建 Android 应用的功能。该构建系统可以作为集成工具从 Android Studio 菜单运行,也可从命令行独立运行。基于 Gradle 的项目提供适用于 Android 开发的重要功能,包括支持二进制文件库(AAR)。无需再将库源代码复制到自己的项目中,而是只需声明依赖项,即可自动下载库并将其合并到项目中。这包括在构建时自动合并资源、清单条目、Proguard 排除规则和自定义 lint 规则等。
如果您使用 Kotlin(推荐),则 Android Studio build 文件名为build.gradle.kts;如果您使用 Groovy,则名为build.gradle。它们是使用 Android Gradle 插件提供的元素以 Kotlin 或 Groovy 语法配置 build 的纯文本文件。每个项目都有一个用于整个项目的顶级 build 文件,以及用于各模块的单独模块级 build 文件。在导入现有项目时,Android Studio 会自动生成必要的 build 文件。
注意:我们可能会在文档中仅引用
build.gradle.kts或build.gradle文件,但它们在概念上可以互换。例如,如果您看到build.gradle.kts,但您使用 Groovy DSL 配置 build,则可以将其视作build.gradle文件。反之亦然。
1 什么是 build?
构建系统将源代码转换为可执行应用。构建通常涉及多个工具,用于分析、编译、关联和打包应用或库。Gradle 使用基于任务的方法组织和运行这些命令。
任务封装了将输入转换为输出的命令。插件用于定义任务及其配置。将插件应用于 build 会注册其任务,并使用其输入和输出将它们连接在一起。例如,将 Android Gradle 插件(AGP)应用于 build 文件后,系统会注册构建 APK 或 Android 库所需的所有任务。借助 java-library 插件,您可以从 Java 源代码构建 jar 文件。Kotlin 和其它语言都存在类似的插件,但其它插件旨在扩展插件。
Gradle 更倾向于采用惯例而非配置,因此插件会直接提供良好的默认值,但您也可以通过声明式域特定语言(DSL)进一步配置 build。DSL 的设计宗旨是让您可以指定要构建的内容,而不是构建方式。插件中的逻辑负责管理“如何”。该配置是在您的项目(和子项目)内的多个 build 文件中指定的。
任务输入可以是文件和目录,以及编码为 Java 类型(整数、字符串或自定义类)的其它信息。输出只能是目录或文件,因为它们必须写入磁盘。将任务输出连接到另一个任务输入,会将任务关联在一起,以便一个任务必须在另一个任务之前运行。
虽然 Gradle 支持在 build 文件中编写任意代码和任务声明,但这可能会使工具更难以理解您的 build,并且会增加维护难度。例如,您可以在插件中为代码编写测试,但不能在 build 文件中编写测试。您应将构建逻辑和任务声明限制为使用您或他人定义的插件,并声明您希望如何在构建文件中使用该逻辑。
2 Gradle build 运行时会发生什么?
Gradle 构建分三个阶段运行。其中每个阶段都会执行您在 build 文件中定义的不同代码部分。
- 初始化:用于确定 build 中包含哪些项目和子项目,并设置包含 build 文件和应用的插件的类路径。可以在设置文件中声明要构建的项目以及要从中提取插件和库的位置。
- 配置:会为每个项目注册任务,并执行 build 文件以应用用户的 build 规范。请务必注意,配置代码将无法访问在执行期间生成的数据或文件。
- Execution:用于执行实际的应用“构建”。配置的输出是任务的有向无环图,表示用户请求的所有必需构建步骤(在命令行中提供的任务或 build 文件中作为默认值的任务)。此图表示任务之间的关系,可以在任务声明中明确显示,也可以基于其输入和输出。如果某个任务的输入是另一个任务的输出,则该任务必须在另一个任务之后运行。此阶段会按照图中定义的顺序运行过期任务;如果任务的输入自上次执行以来未发生更改,Gradle 将跳过该任务。
3 配置 DSL
Gradle 使用特定领域的语言(DSL)来配置 build。这种声明方式侧重于指定数据,而不是编写分布(命令式)指令。您可以使用 Kotlin 或 Groovy 编写 build 文件,但我们强烈建议您使用 Kotlin。
DSL 旨在让所有人都能更轻松地为项目做出贡献,通过定义一种小型语言以更自然的方式表示数据。Gradle 插件可以扩展 DSL,以配置其任务所需的数据。
DSL 中的每个块都由一个函数表示,该函数接受一个 lambda 来对其进行配置,以及一个同名属性来访问它。这使得 build 文件中的代码更像是一个数据规范。
4 管理依赖项
项目的依赖项在模块级构建脚本中按名称指定。Gradle 会查找依赖项,并在 build 中提供这些依赖项。您可以在build.gradle(.kts)文件中声明模块依赖项、远程二进制依赖项以及本地二进制依赖项。
Android Studio 配置项目时默认使用 Maven 中央仓库。该配置包含在项目的顶级 build 文件中。
4.1 外部依赖项
Maven 构建系统引入了依赖项规范、存储和管理系统。库储存在代码库(服务器或目录)中,其中包含元数据,包括版本和对其它库的依赖项。您可以指定要搜索的代码库、要使用的依赖项版本,并且构建系统在构建期间会下载这些依赖项。
Maven 工件通过组名称(公司、开发者等)、工件名称(库的名称)和该工件的版本进行标识。这通常表示为group:artifact:version。
此方法可显著改善构建管理。您经常会听到有人将此类仓库称为“Maven 仓库”,但这完全取决于工件的打包和发布方式。这些代码库和元数据已在多个构建系统中重复使用,包括 Gradle(Gradle 可以发布到这些代码库)。公共代码库可供所有人共享使用,而公司代码库可将内部依赖项保留在内部。
您还可以将项目拆分为子项目(在 Android Studio 中称为“模块”),这些子项目还可以用作依赖项。每个子项目都会生成可供子项目或顶级项目使用的输出(例如 jar 文件)。这可以通过隔离需要重新构建的部分来缩短构建时间,并更好地分离应用中的职责。
5 build 变体
在开发 Android 应用时,您通常需要构建多个变体。变体包含不同的代码或使用不同的选项构建,并且由 build 类型和产品变种组成。
build 类型会使声明的 build 选项有所不同。默认情况下,AGP 会设置“release”和“debug” build 类型,但您可以对其进行调整并添加更多类型。
调试 build 不会缩减应用的大小或对其进行混淆处理,从而加快其构建速度并保留所有符号。它还会将应用标记为“可调试”,使用通用调试密钥为其签名,并允许访问设备上已安装的应用文件。这样一来,您就可以在运行应用时浏览文件和数据库中保存的数据。
发布 build 会优化应用,使用发布密钥为其签名,并保护已安装的应用文件。
通过使用产品变种,您可以更改应用包含的源代码变体和依赖项变体。例如,您可能需要为应用创建“demo”和“full”变种。您可以在“主”源代码集目录中编写通用源代码,并在以特定变种命名的源代码集中替换或添加源代码。
AGP 会为 build 类型和产品变种的每个组合创建变体。如果您未定义变种,则变种将以 build 类型命名。如果您同时定义两者,则变体将命名为<flavor><Buildtype>。例如,如果 build 类型为release和debug,变种为demo和full,AGP 将创建以下变体:
demoReleasedemoDebugfullReleasefullDebug
6 Android build 结构
Android 项目包含许多与构建相关的文件和目录结构, 组织您的应用来源和资源。下面列出了 Android 项目中的典型文件。每个文件或目录中的描述,包含有关该目录内容类型的备注。最佳做法会随着时间的推移而不断变化,这些说明可能与从互联网继承或下载的资源不再匹配。
编写 build 文件时,请使用声明式方法;构建逻辑和任务只应出现在插件中。通过将构建逻辑限制在插件中, 构建文件变成了数据声明,这样更便于理解和编辑。未来的版本可能会包含替代规范,如声明式 Gradle。
.gradle/:Gradle 项目缓存目录。由 Gradle 管理,包含下载的 Gradle 发行版、项目缓存和配置文件。请勿更改此目录中的文件!.idea/:Android Studio 项目元数据。请勿更改此目录中的文件!build.gradle(.kts):根 build 文件。应仅包含用于设置跨子项目通用插件类路径的插件声明。其他代码应位于设置或嵌套项目级 build 文件中。gradle.properties:Gradle 执行配置。包含 Gradle 属性,用于控制 Gradle 构建环境方面,例如堆大小、缓存和并行执行。此处定义了一些临时的 Android 属性,以便在添加和移除 AGP DSL 时减少对 AGP DSL 的更改。gradlew(Linux、Mac)或gradlew.bat(适用于 Windows):Gradle 封装容器文件。通过下载 Gradle 发行版并将命令转发给它来引导 build。这样一来,您无需预安装 Gradle 即可运行构建。local.properties:本地机器配置。包含与本地计算机相关的属性,例如 Android SDK 的位置。从源代码控制系统中排除此文件!settings.gradle(.kts):Gradle build 初始化。包含 Gradle 初始化和项目配置的全局构建信息,例如:(1)项目名称;(2)要包含在此 build 中的子项目的列表;(3)用于查找插件和依赖项的仓库规范;(4)外部版本目录导入。gradle/:libs.versions.toml:版本目录。定义 build 中使用的依赖项和插件的变量。您可以在此处指定要使用的版本,以确保项目中的所有子项目之间的一致性。wrapper/:gradle‐wrapper.jar:Gradle 引导加载程序可执行文件。下载指定的 Gradle 发行版(如果不存在),并运行该发行版,并传递任意参数。gradle‐wrapper.properties:Gradle 封装容器的配置。指定 Gradle 发行版的下载位置(包括要使用的版本)。
app/:子项目目录。子项目(在 Android Studio 中称为“模块”)可以构建应用或库,并可能依赖于其他子项目或外部依赖项。app 是顶级应用子项目的常规名称(但不是必需名称)。其他子项目具有类似结构,但名称也不同。任何目录都可以是子项目,必须至少包含一个 build.gradle(.kts) 文件,并使用 settings.gradle(.kts) 包含在 build 中。build.gradle(.kts):子项目级 build 文件。声明如何构建此子项目。每个子项目都需要一个单独的 build 文件,并且应包含:(1)用于构建此子项目的插件;(2)插件所需的配置块;(3)构建此子项目时包含的依赖项(库和平台)。您不应在 build 文件中包含构建逻辑(例如 Kotlin 函数定义或条件)或任务声明。构建逻辑和任务只能包含在插件内。src/:子项目源文件。将源文件(应用代码和资源)分组为源代码集。main 源代码集包含所有变体共有的源文件,而其他源代码集包含某个变体独有的源文件。main/:主源代码集。所有 build 变体之间通用的源代码和资源。此源将作为所有构建的基础,并且会添加或替换其他更具体的源集。java/:同下kotlin/:Kotlin 和 Java 源代码。java 目录可同时包含 Java 和 Kotlin 源代码。如果此子项目仅包含 Kotlin 代码,您可以将此目录重命名为 kotlin。Android,将其作为一个 Kotlin 优先平台。支持 Java 源代码,但新的 API 以 Kotlin 语言为目标平台。我们建议针对所有新代码和对现有代码进行重大更新使用 Kotlin。res/:Android 资源文件。包含应用资源,例如 XML 文件和图片。所有应用都会使用一些基本资源(例如启动器图标),但其中许多资源(例如布局和菜单)仅用于基于视图的应用。Compose 应用使用此目录下定义的 String 资源。AndroidManifest.xml:Android 应用元数据。由 Android 软件包管理器读取,以告知系统:(1)由您的应用定义的组件;(2)必要权限;(3)设备兼容性;(4)Android 平台限制。
androidTest/:设备测试源代码集。包含在 Android 设备或模拟器上运行的测试的源代码。这些测试可以访问真实的 Android 环境,但执行速度比主机测试慢。main 源代码集中的所有源文件都可供 androidTest 下的源代码使用。test/:主机测试源代码集。包含在 JVM 本地运行的测试(而不是在设备上运行的测试)的源代码。这些测试的运行速度比设备测试快得多。但是,您必须模拟、伪造、打桩或以其他方式模拟任何系统调用(包括运行应用的生命周期)。main 源代码集中的所有源文件都可供被测源代码使用。
proguard-rules.pro:R8 配置规则。定义用于控制应用缩减、优化和混淆的规则。R8 移除了不需要的代码和资源,优化运行时性能,并通过重命名标识符进一步最大限度地减少代码。
1003

被折叠的 条评论
为什么被折叠?



