在 Android Studio 里使用构建分析器提升构建性能

作为 Android 开发者工具团队的成员,我和团队成员们每天都抱着将 Android 打造成最好的移动开发者平台的想法来制作各种工具。这意味着我们会构建一些帮助您开发应用的工具,让您专注于编写应用。

我们知道超长的构建既浪费时间也会打断开发流程,并且会让开发者十分沮丧。Android Studio 用户平均每周构建 65 次,所以即便每次构建只慢 10 秒钟也会浪费每个开发者一年大约 9 个小时的时间。尽管如此,如我们在稍早的文章《在 Android Studio 中优化构建速度》提到的,大约有 60% 的 Android 开发者不会去做构建分析。再加上不断增长的项目复杂度,最终导致了所有使用 Android Studio 的项目构建时间不断增长,也严重影响了开发效率。

为了解决这个问题,我们制作了构建分析器。这个工具可以帮助所有开发者理解影响他们项目构建时间的因素,以及如何减少这些因素的影响。

充分使用构建分析器 (Build Analyzer) 提供的功能

每次构建应用,Android Studio 都会生成一个构建分析器报告。为了看到这个报告,请确保您按照如下步骤操作:

  1. 升级 Android Gradle Plugin 到 4.0.0 或更高版本。
  2. 构建或者重新构建您的工程。
  3. 通过选择 View > Tool Windows > Build 菜单来访问构建分析器,然后点击 Build Analyzer 标签。

Santa Tracker 应用是 Google 开发的一个教程性质的开源应用,为了这篇文章,我们将 clean build 这个应用,并和大家一起理解生成的构建分析报告。

打开构建分析器,您会看到 Overview 页面。这个页面展示了一些基本信息以及跳转到各个详情页的链接。如下图所示,我们立即就会发现,这个构建的耗时主要来自于任务执行而不是构建的配置。

为了了解更多,让我们来继续深入分析构建分析器所提供的两个数据集。它们分别是 Tasks (任务)Warnings (警告)。您既可以通过 Common views into this build 下的链接来访问,也可以通过左上角当前显示 “Overview” 的下拉菜单来切换。

任务

这些任务决定了刚刚观察到的构建时间,其中有的是因为输入、输出的依赖关系,而其他的则是由于并行构建的约束。除此之外的任务,可以并行运行并且不会对构建时间有影响。查看这个面板可以告诉我们构建应用的哪个步骤是最耗时的。

当展开列表来查看这些任务的时候,每个任务会根据来源显示为不同的颜色。来自 Project Customizations 的任务是由您项目的本地自定义的,也是最容易被修改的。被标示为 Android/Java/Kotlin Plugins 的任务来自于核心插件。而 Other Binary Plugins 的任务要么是来自您团队成员编写的二进制插件,或者是来自第三方制作的二进制插件。

默认情况下这些任务会以展开列表的形式显示,但是也可以使用 Group by plugin 选项来按照任务来源的插件分组。这样分组会将您项目中的每个插件显示为一个节点,而不是按照单个任务来显示。

这样分组会让我可以观察到,我项目构建的大部分时间是在执行来自核心插件的任务,比如 Kotlin 或者 Android Gradle 的插件。这并不意外,尤其是在对于像 Santa Tracker 一样的项目运行全量构建的时候。而在运行增量构建的时候,核心插件的任务通常会耗费相对较少的时间,这样会便于我们发现其他插件对于构建时间的影响。

当我们需要比较添加或者升级某个插件对于构建时间影响的时候,这个插件视图格外有用,因为它会帮助您权衡更改的好处和它们对于构建时间带来的影响。无论什么时候,对于更改的谨慎是防止我们不断地增加项目构建时间的最好办法,也就能避免其影响我们的开发效率。

警告

这个视图可以让您看到该构建生成的所有警告,其中也包括了那些并不会影响构建时间任务的警告。

每个警告信息都会包含其产生的原因和推荐的解决办法,以及如果适用的话,也会包含生成该警告的任务的详细信息。如果该警告不是来自您的团队成员的插件,您可以使用 Generate report功能来向该任务或插件的作者进行反馈。

如上图显示,在使用构建分析器分析我们之前提到的 Santa Tracker 项目时,生成了一个 Task Setup 警告。这个问题看起来是由于输出目录冲突造成的,所以我们可以修改 generateExtraResources 任务和 mergeDebugResources 任务其中之一的输出文件路径。mergeDebugResources 任务来自于 android 基础插件,并且不能在本地修改。generateExtraResources 任务被标示为 project customization 且该任务是我的团队制作的。基于此我决定修改 generateExtraResources 任务。

另外需要注意的是,上面的报告来自于全量构建,而增量构建的报告之间会不太一致,但却可能更真实地反映您平时的开发流程。所以在使用构建分析器的时候,请确保您使用了全量构建和增量构建。想要了解更多关于构建分析器的内容,请查阅 Android 开发者官方文档|排查构建性能问题

构建分析器如何工作

每当您使用 Android Studio 构建您的项目,构建分析器会使用 Gradle Tooling APIAndroid Gradle Plugin 在本地收集数据。Tooling API 会被用来绑定 ProgressListener,它会提供关于项目的配置、任务执行、注解处理器等信息。Android Gradle 插件会提供更多的其他信息,包括任务名称和任务类名的映射,以及任务的配置信息。

当您的构建结束的时候,构建分析器会将这些信息输入一系列的分析器,每个分析器会找到并报告特定的问题。举个例子,有一个分析器会检查那些被设置为每次构建都需要执行的任务,因为这些任务会阻碍增量构建节省时间,而这会严重影响构建速度。

那这个分析器是如何发现那些每次都执行的任务呢?当一个 Gradle 任务的输入或输出对比上一次构建没有变化的时候,这个任务被认为是 up-to-date 的。当一个任务是 up-to-date,Gradle 会跳过执行该任务并复用这个任务以前的输出,而不是浪费时间重新执行它。如果一个任务没有声明输入或输出,那它永远不会认定为 up-to-date。这个分析器依靠 Gradle Tooling API 提供的任务输出信息找到所有有问题的任务,它们要么是没有声明任何输出,要么是替换 up-to-date 为 false。通过这个方法,这个分析器可以找到所有永远不会 up-to-date 的任务,而这些任务每一次构建都会运行。我们希望可以利用这个分析器帮助您快速地定位问题,并开始充分利用增量构建。

目前除了这个可以识别每次构建都运行的任务的分析器,还有其他两个分析器。其中一个可以识别 非增量的注解处理器,另外一个可以识别任务之间替换彼此的输出。未来我们计划继续发布各种分析器,来帮助您快速地发现常见问题以及掌握关于使用 Gradle 的最佳实践。

后续行动

如果构建分析器报告了一个来自第三方插件任务的警告,您可以考虑向插件的原作者提交 bug 报告。类似的问题有可能不会被立即解决,但是这会帮助整个生态变得更好。如果您认为这个问题来自构建分析器本身,请通过我们的 issue tracker 来让我们知道。

如果您有兴趣深入理解您的项目构建,请尝试用 Gradle Scan 来获取更多额外的信息。此外,使用 Gradle 的 Build Cache 也可能减少您的构建时间。

随着这个工具逐渐成熟,我们希望能够扩展分析器套件来识别更多的警告。我们热切地希望了解人们是如何使用这个工具,同时我们也会继续改进跳转浏览、图形化和其他相关组件。如果您有任何反馈,尤其是那些您在自己的项目构建中发现的,但是没有被我们的分析器捕获到的问题,请告知我们。