给Android开发者的Gradle入门指南
本文的目的是为您提供关于 Gradle 的高级概述,以及在开发 Android 应用程序时如何适应整个构建系统。 我将通过 Gradle 和 Gradle 的 Android 插件的基础知识,以及新的 Android 项目附带的默认 build.gradle 脚本来进行讲述。
本文不会教你如何编写定制的 Gradle 脚本或任何类型的东西。正如标题所说,这是给真正意义上的初学者的文章。
背景故事
我先坦白一下:我主要是一名 iOS 开发人员。在整个职业生涯中,只有四分之一的时间用于开发 Android 应用程序。正因为如此,我从来没有真正理解 Gradle 是什么。当我点击 Android Studio 中的绿色播放按钮时,我知道这是“工作”,但我不知道它实际上做了什么。
当我看到“ Gradle Build Running ”这个词超过 10 秒时,这让缺少相关知识的我非常不耐烦。 “有什么需要这么久?”我会问 Android Studio ,希望有某种迹象表明它不仅仅是卡住了。在工作中,每当我看到一个 Android 开发者茫然地盯着屏幕,我经常开玩笑地问他们:“你是在等 Gradle 构建吗?
最终我感到沮丧,并决定找出要如何减少构建时间。我看了一个名为“ 加快 Android 的 Gradle 构建 ”的 Google I/O ’17 的演讲,相信会解开所有我想要的提升 Gradle 速度的关键。
40分钟之后,我意识到我对 Gradle 一无所知,所以我根本没有机会做得更好。 我停下脚步,决定现在是去理解 Gradle 的时候了。
基础知识
为了解决这个问题,让我们先弄清楚一些事情:
- Android Studio 不知道如何将 Java&Kotlin 代码编译成 APK 文件。
- Gradle 不知道如何将 Java&Kotlin 代码编译成 APK 文件。
是的,你没看错。
Gradle 本身并不知道如何编译 APK 文件,因为 Gradle 实际上是一个 通用的构建工具 。它不限于构建 Android 应用程序。在 Gradle 的 GitHub 仓库 中,它被描述为:
...构建工具,着重于构建自动化和支持多语言开发。如果您在任何平台上构建、测试、发布和部署软件,Gradle 提供了一个灵活的模型,可以支持从编译和打包代码到发布的整个开发生命周期。 Gradle 本身实际上并不能做太多。所有有用的功能都来自丰富的插件生态系统。把你添加到 Android 应用程序中的所有第三方库视为插件。您可以使用这些插件来扩展应用程序的功能,就像 Gradle 使用插件来扩展自己的功能一样。
有很多与 Gradle 捆绑 在一起的插件,以及更多 可以下载的插件 。但是,如果你阅读 Gradle 附带的插件列表,则会发现在该页面上找不到“Android”。
Android Plugin for Gradle
Android Plugin for Gradle 是一个使 Gradle 能够将您的代码编译成用你的密钥签名 APK 文件的插件,甚至将 APK 安装到你的模拟器或测试设备上。这个插件驱动你的整个构建系统。
没有它,Gradle 就无法知道如何对代码做任何事情。这也就是我前面说的 Android Studio 和 Gradle 不知道如何构建你的 Android 项目:这个插件是 Android Studio 和 Gradle 之间的魔法链。
深入脚本
现在我们已经掌握了一些基础知识,接下来看看如何转化为日常实现。当你在 Android Studio 中启动一个全新的项目时,会获得以下文件:
这些文件是什么?
所有带有“ gradle ”文字的文件都用于为我们的 Android 项目配置 Gradle 。里面存在多个文件,因为它们都有不同的用途。
Gradle Wrapper
gradle-wrapper.properties 文件有一个简单的目的:决定在构建项目时使用哪个 Gradle 版本。它将随后会自动为你下载并保存该版本的 Gradle 。如果你在 Mac 上使用,运行下面命令 ls ~/.gradle/wrapper/dists/ 你就可以看到 Gradle Wrapper 曾为你下载过的所有 Gradle 版本。
注意你的 Gradle 版本是独立于你的 Android 插件版本的。在本文撰稿时,目前 最新的 Gradle 版本是 v4.3 。Android Studio 依然默认使用 v4.1 ,所以如果你愿意,你可以很安全的将版本升级到 v4.3 。
settings.gradle
settings.gradle 文件是保存在你通知 Gradle 的地方,即你的工程所有的子工程 /module 目录下。这是通过 include 命令完成的。如果你将另一个模块添加到你的工程中,Android Studio 将会自动将其添加到这个文件中。
build.gradle
从 Gradle 的角度来看,我们的工程被认为是一个 多工程构建, 其中你拥有一个根项目以及一个到多个子工程。从 Android 开发者的角度来看,这些子工程被称为 module (模块)。
这就是为什么你会看到两个 build.gradle 文件的原因。一个是给根项目的,另一个是给伴随着你的项目的 app 模块的。让我们先看看你的根项目的格式吧。
- 这个完整的 buildscript {} 块用于告知 Gradle 脚本本身,关于编译本项目需要的那些。
- 我们在这个 buildscript 中声明了 Android Gradle 插件的依赖性。“3.0.0” 表示要使用的插件版本。
- 我们告知 Gradle 我们需要到 google() Maven 代码库和 jcenter() 代码库中检索一些事项。
- 在Gradle 项目中添加 额外的属性 ,以支持它可以在整个 Gradle 项目中是可访问的。换言之,这是 Gradle 风格的全局变量。我们可以通过使用决定所导入的 kotlin-gradle-plugin 的版本的方式来查看该变量的值。
- 正如名字所暗示的, allprojects{} 块被用于通知 Gradle 关于所有需要编译的子项目,并使用这个代码库集合来解决所有需要的依赖项。
- 首先,我们应用真实的 Android 插件,然后我们使用 其扩展插件 来应用 Kotlin Android 插件。
- 此完整的 android{} 块工作的唯一原因是因为我们要求 Gradle 使用之前提到的 Android 插件。我深信你对修改该模块内部的值非常熟悉,但你是否对所有可能放入该块的值有过好奇呢?好事情是它 在此都被文档化了!
- 这里就是你添加 Gradle 所依赖的第三方库的位置。注意在你的 app 的 build.gradle 中并没有 repositories{} 块。既然我们已经在根项目的 allprojects{} 块中声明了,这里就没有必要了。
- 还记得我们在根构建文件中的全局变量吗?是的,这里就是起作用的地方。最好采用类似 管理你所支持库的版本 一样的策略可能是个不错的主义,这可以保证他们都是用同一个版本。
Gradle 任务
现在我们透过脚本,还有一件你必须知道的关于 Gradle 的事:任务。
任务是基本的东西,Gradle 可以每当被触发时生成,记得早前(上文)我说 Android Studio 其实不知道如何编译你的代码?因为在 Android Studio 点击大绿色的 play 按钮会触发一个具体的任务在 Gradle 执行。
在右下角,点击 “Gradle Console” 按钮去打开 Gradle Console ,然后点击 play 按钮运行 app ,一大堆命令会出现,但我们只关心顶部的:
Executing tasks: [:app:assembleDebug]
我们只讨论 Gradle 执行的 assembleDebug 任务,我们可以通过命令行来做相同的事,点击左边的 Terminal 按钮并运行本段代码:./gradlew assembleDebug --console plain
瞧!你只是让 Gradle 运行与播放按钮完全相同的命令。有几件事要注意:
- ./gradlew 意味着使用 Gradle Wrapper 来代替 “vanilla” Gradle 。强烈建议您始终使用 Wrapper 版本。
- assembleDebug 是你刚刚要求它运行的任务的名称。
- --console plain 告诉 Gradle 打印生成日志,就像你在 Android Studio 中看到的一样。完全是可选的。
让我们运行最后一个命令:./gradlew tasks
这个命令将列出 Gradle 目前在这个项目中所知道的所有任务,并提供每个任务的简短描述。很酷吧?
现在,点击 Android Studio 右上角的 Gradle 标签。
哈哈!这是一样的东西。这一部分只是列出了 Gradle 可以为这个项目运行的所有可能的任务。在这里双击 assembleDebug ,就可以做到与刚刚在命令行上做的一样的事情,并且和播放按钮做同样的事情。
如果您在 Android Studio 中运行“重建项目”命令,同时保持 Gradle 终端处于打开状态,你将会意识到它所做的只是运行 clean 任务,然后运行 assembleDebug 命令。这就是我发现在重建项目之前运行清理项目是完全不必要的,因为重建项目无论如何都会运行相同的 clean 任务。