最新版提升 Android 应用编译速度的方法


应用的构建速度会直接影响开发效率,本文将带您通过改造一个 Android 应用: “Google 追踪圣诞老人 (Google Santa Tracker)” 来为大家提供十个小技巧,帮助提升应用的 Gradle 构建速度,当我们应用了所有的小技巧之后,该演示应用的构建速度快了三倍以上。

开源实验室

首先来了解一下 “Google 追踪圣诞老人” 应用的工程背景: 这个应用有约 60M 大小,它包含 9 个模块,有 500 多个 Java 文件,1,700 多个 XML 文件、3,500 多张 PNG 图片资源,用到了 Mutil-dex,没有注解处理器。

其次,在我们开启速度提升调优之前,来了解本次三个性能指标的说明:

  • 全量构建,也就是重新开始编译整个工程的 debug 版;

代码增量构建,指的是我们修改了工程的 Java / Kotlin 代码;

资源增量构建,指的是我们对资源文件的修改,增加减少了图片和字符串资源等。

每个小技巧实施以后,我们会对比如上三个场景的构建时间以作为我们的量化标准。请注意,由于工程规模大小不一、开发环境各异,开发者们在实际的操作中的结果可能会与本文的结果有所不同。

使用最新版本的 Android Gradle 插件

开源实验室
每次 Android Gradle 插件的更新都会修复大量的 bug 及提升性能等新特性,因此保持最新的 Android Gradle 插件版本有非常大的必要。

从 3.0 版本开始,我们将通过 google() 的 Maven 仓库分发新的 Android Gradle 插件,所以需要在 repositories 处加入 google() 以获得最新的插件更新 (现在的 Android Studio 新建工程的时候会默认加入 google() 的 Maven 仓库指向)。

开源实验室

这是将 Android Gradle 插件版本从 2.x 更新到 3.0.0-alpha1 之后得到的结果 (这里的演示是基于 3.0.0-alpha1 版本,随着插件版本的更新,性能的提升会更加明显),我们可以看出,全量构建一次应用的时间直接减少了 25%,代码改动的增量构建减少了将近 40%,资源改动的增量构建也减少了 16%。

避免激活旧版的 Multidex

开源实验室

这个小技巧大家应该比较熟悉——避免激活旧版的 multidex。当您的应用配置方法数超过 64K 的时候,您需要启用 multidex。当您启用了 multidex,且工程的最低 API 级别在 21 之前时,旧版的 multidex 就会被激活,这将严重拖慢您的构建速度,原因是 21 之前的 API 级别并没有原生的支持 multidex。关于启用 multidex请查看 官方文档

如果您是通过 Android Studio 的运行/调试按钮来执行构建,那么无需考虑这个问题,新版本的 Android Studio 会自动检测连接的设备和模拟器,如果系统的 API 级别大于 21 则进行原生的 multidex 支持,同时会忽略工程里对最低 API 级别 (minSdkVersion) 的设置。

习惯通过命令行窗口构建工程的开发者们则需要试着避免这个问题: 配置一个新的 productFlavor,设定工程的最低 API 级别为 21 或者以上,在命令行里调用 assembleDevelopmentDebug 即可避免这个问题。

开源实验室

这一次的性能改进结果效果也非常明显 (灰色的线条是最初的结果),在全量构建的时候我们又降低了 5.5 秒的时间,而在代码改动的增量构建里时间减少了 50% 以上,资源改动的增量构建与之前的时间相同。

最小化使用资源文件

开源实验室 当您的应用包含大量本地化资源或者为不同像素密度加入了特别的资源时,您可能需要应用这个小技巧来提高构建速度——最小化开发阶段打包进应用的资源数量。

构建系统默认会将声明过或者使用过的资源全部打包进 APK,但在开发阶段我们可能只用到了其中一套而已,针对这种情况,我们需要使用 resConfigs() 来指定构建开发版本时所需要用到的资源,如语言版本和屏幕像素密度。

开源实验室

这里我们看到了较大程度上的改观,全量构建的时间又降低了 6 秒,增量构建的时间也分别降低了 20% 以上。

禁用 PNG 压缩

开源实验室 与小技巧 4 一样,这个特性本身在打包发布阶段是相当有帮助的—— PNG 压缩,但在开发阶段禁用这个功能可以提高构建效率。默认情况下,AAPT 会压缩工程的 PNG 资源以减小 APK 体积,根据图片的数量和大小,这个过程所消耗的时间有长有短。

开源实验室 如果要避免使用 PNG 压缩,我们可以在小技巧 3 里提到的,在 devBuild 属性里加入 aaptOptions.cruncherEnabled = false 来实现,在构建的过程中把这个值传给 gradle,它就可以避免执行 PNG 压缩命令了。

开源实验室

另外一个避免压缩 PNG 的方法是使用把 PNG 转换成 WebP 格式的图片,对比 PNG 格式,WebP 可以减少最多 25% 的大小,同时 2.3 以上版本的 Android Studio 直接支持 PNG 到 WebP 格式的转换。

需要注意的是,API 级别 15 及更高可以支持不透明的 WebP 格式图片,如果是透明格式的 WebP,需要 API 级别 18 以及更高。

开源实验室

这可以看到全量构建又减少了 9 秒的时间,这也是因为 Google 追踪圣诞老人应用里有 3,500 多张 PNG 图片,这要花费大量的时间进行压缩计算,所以这方面的效率提升显得很明显,而其他增量构建只是维持了之前的情况。

特别提出一下关于 APK 体积的问题——对比了启用和禁用 PNG 压缩之后的 APK 体积之后,我们发现前后的体积并没有太大改变,这说明该工程里使用的 PNG 图片在导入之前已经经过了充分优化,PNG 压缩在这里实属多此一举。

使用 Apply Changes

开源实验室

从 Android Studio 3.5 版开始 (3.5 版目前在 Beta 构建渠道发布),开发者们可以使用 Apply Changes 功能来提高构建性能,它可以让代码和资源的改动直接生效而无需重启应用,有时候甚至无需重启当前的 Activity。与 Instant Run 的实现方式不一样,Apply Changes 充分利用了 Android 8.0 以上版本操作系统的特性进行运行时检测,从而动态的对类进行重新定义。因此,如果您希望使用 Apply Changes,则需要让您的工程运行在 Android 8.0 (API级别26) 以上的真机或者模拟器上。

不使用动态版本标识

开源实验室

Gradle 提供了一个非常方便的依赖库版本号管理功能,方便开发者们通过使用一个加号 “+” 标识希望使用这个依赖库的最新版本。但是使用动态版本有几个风险,从性能角度来说,Gradle 会每隔 24 小时去检查一次依赖库的更新,如果您的依赖库很多,而且都使用了动态获取最新版本的这个设定,那会对构建时候的性能产生一定的影响。

即使您不是特别在意这些性能损耗,但他还有一个你必须在意的风险点——具体见我这篇文章 《如何在 Android 代码中下毒》。

Gradle 内存分配调优

开源实验室

默认的构建环境里,我们会给 Gradle 分配 1.5G 的内存,但这个并非适用于所有的项目,您需要通过对这个数字对调优来得到适合您工程的最佳 Gradle 内存分配。

与此同时,从 Android Gradle 插件 2.1 版本之后,dex 已经默认在进程里了,所以如果您之前设定过 javaMaxHeapSize 值,可以选择删掉它了。

开启 Gradle 构建缓存

开源实验室

Gradle 新推出的缓存机制效果非常出色,我们建议大家尝试开启,最新的 Gradle 支持了 Kotlin 项目使用构建缓存,构建速度可以提高很多。Gradle 的构建缓存默认是不开启的,您可以通过在命令行里加入 --build-cache 参数或者在工程根目录的 gradle.properties 里加入 org.gradle.caching=true 为所有人启用构建缓存。您可以在这个文档里了解更多关于 Gradle 构建缓存的内容。

点击访问关于 Gradle 构建缓存