优化Android Studio构建速度

构建时间太长会拖慢您的开发过程。本页将介绍一些有助于解决构建速度瓶颈的技巧。

提高应用构建速度的一般过程如下:

  1. 采取一些对大多数 Android Studio 项目立竿见影的措施,优化 build 配置
  2. 对构建进行性能剖析,确定并诊断一些对您的项目或工作站来说比较棘手的瓶颈问题。

开发应用时,您应尽可能将其部署到搭载 Android 7.0(API 级别 24)或更高版本的设备中。较新版本的 Android 平台有更出色的机制来向您的应用推送更新,例如 Android 运行时 (ART) 以及对多个 DEX 文件的原生支持。

注意:您完成首次干净构建后,可能会注意到后续构建(干净和增量)的执行速度明显加快了(即使您没有使用本页面介绍的任何优化措施)。这是因为 Gradle 守护程序有一个性能提升“预热”期,类似于其他 JVM 进程。

优化 build 配置

按照下面的提示操作,以提高 Android Studio 项目的构建速度。

保持工具处于最新状态

几乎每次更新时,Android 工具都会获得构建方面的优化和新功能,本页介绍的一些提示假设您使用的是最新版本。为了充分利用最新的优化措施,请确保以下工具始终是最新版本:

避免编译不必要的资源

避免编译和打包不测试的资源(例如,其他语言本地化和屏幕密度资源)。您可以仅为“dev”变种的版本指定一个语言资源和屏幕密度,如下面的示例中所示:

android {
    ...
    productFlavors {
        dev {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations "en", "xxhdpi"
        }
        ...
    }
}
尝试将 Gradle 插件门户放置在最后

在 Android 中,所有插件都位于 google() 和 mavenCentral() 代码库中。不过,build 可能需要使用 gradlePluginPortal() 服务解析的第三方插件。

Gradle 会按照声明的顺序搜索代码库,因此,如果先列出的代码库包含大多数插件,build 性能就会得到提升。因此,您可以尝试将 gradlePluginPortal() 条目放置在 settings.gradle 文件的代码库中最靠后的位置。在大多数情况下,这样可以最大限度地减少冗余插件搜索次数,并提高构建速度。

如需详细了解 Gradle 如何导航多个代码库,请参阅 Gradle 文档中的声明多个代码库

将静态 build 配置值用于调试 build

始终为会进入调试 build 类型的清单文件或资源文件的属性使用静态值。

您每次想运行更改时,都需要完整的应用 build 才能使用动态版本代码、版本名称、资源或可更改清单文件的任何其他构建逻辑,即使实际更改可能仅需要 1 次热交换也是如此。如果您的 build 配置需要此类动态属性,请将这些属性隔离到您的发布 build 变体中,并使相应值对您的调试 build 保持静态,如下例所示:

  ...
  // Use a filter to apply onVariants() to a subset of the variants.
  onVariants(selector().withBuildType("release")) { variant ->
      // Because an app module can have multiple outputs when using multi-APK, versionCode
      // is only available on the variant output.
      // Gather the output when we are in single mode and there is no multi-APK.
      val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

      // Create the version code generating task.
      val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
          it.outputFile.set(project.layout.buildDirectory.file("versionCode${variant.name}.txt"))
      }

      // Wire the version code from the task output.
      // map will create a lazy Provider that:
      // 1. Runs just before the consumer(s), ensuring that the producer (VersionCodeTask) has run
      //    and therefore the file is created.
      // 2. Contains task dependency information so that the consumer(s) run after the producer.
      mainOutput.versionCode.set(versionCodeTask.flatMap { it.outputFile.map { it.asFile.readText().toInt() } })
  }
  ...

  abstract class VersionCodeTask : DefaultTask() {

    @get:OutputFile
    abstract val outputFile: RegularFileProperty

    @TaskAction
    fun action() {
        outputFile.get().asFile.writeText("1.1.1")
    }
  }

如需了解如何在项目中设置动态版本代码,请参阅 GitHub 上的 setVersionsFromTask 配方

使用静态依赖项版本

在 build.gradle 文件中声明依赖项时,请避免使用动态版本号(以加号结尾的版本号,例如 'com.android.tools.build:gradle:2.+')。使用动态版本号可能会导致意外的版本更新和难以解析版本差异,并会因 Gradle 检查有无更新而减慢构建速度。 请改用静态版本号。

创建库模块

在应用中查找可以转换成 Android 库模块的代码。以这种方式将您的代码模块化,可以让构建系统仅编译您修改的模块,并缓存输出以用于未来的构建。此外,这种方式也会让并行项目执行更有效(当您启用该优化时)。

为自定义构建逻辑创建任务

创建构建性能剖析报告后,如果性能剖析报告显示相当长的一部分构建时间用在了“配置项目”阶段,请检查 build.gradle 脚本并查找您可以添加到自定义 Gradle 任务中的代码。将某些构建逻辑移到任务中后,您可以确保它仅在需要时运行,可以缓存结果以用于后续构建,并且该构建逻辑将可以并行运行(如果您已启用并行项目执行)。如需详细了解自定义构建逻辑的任务,请参阅官方 Gradle 文档

提示:如果您的构建包含大量自定义任务,您可能需要通过创建自定义任务类来整理 build.gradle 文件。将您的类添加到 project-root/buildSrc/src/main/groovy/ 目录中;Gradle 会自动将这些类添加到项目中所有 build.gradle 文件的类路径中。

将图片转换为 WebP 格式

WebP 是一种既可以提供有损压缩(像 JPEG 一样)也可以提供透明度(像 PNG 一样)的图片文件格式,不过与 JPEG 或 PNG 相比,WebP 格式可以提供更好的压缩。

减小图片文件大小可以加快构建速度(无需在构建时进行压缩),尤其是当应用使用大量图片资源时。不过,在解压缩 WebP 图片时,您可能会注意到设备的 CPU 使用率有小幅上升。通过使用 Android Studio,您可以轻松地将图片转换为 WebP 格式

停用 PNG 处理

即使您不将 PNG 图片转换为 WebP 格式,仍然可以在每次构建应用时停用自动图片压缩,以加快构建速度。

如果您使用的是 Android Gradle 插件 3.0.0 或更高版本,则系统会在默认情况下针对“调试”编译类型停用 PNG 处理。如需针对其他 build 类型停用此优化,请将以下代码添加到 build.gradle 文件中:

android {
    buildTypes {
        release {
            // Disables PNG crunching for the "release" build type.
            crunchPngs false
        }
    }
}

由于 build 类型或产品变种不定义此属性,因此在构建应用的发布版本时,您需要手动将此属性设置为 true

使用 JVM 并行垃圾回收器进行实验

通过配置 Gradle 所用的最佳 JVM 垃圾回收器,可以提升构建性能。虽然 JDK 8 默认配置为使用并行垃圾回收器,JDK 9 及更高版本已配置为使用 G1 垃圾回收器

为提高构建性能,我们建议您使用并行垃圾回收器测试 Gradle 构建。在 gradle.properties 中设置以下内容:

org.gradle.jvmargs=-XX:+UseParallelGC

如果此字段中已设置了其他选项,请添加一个新选项:

org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

如需衡量采用不同配置时的构建速度,请参阅对构建进行性能剖析

增加 JVM 堆大小

如果您发现构建速度较慢(尤其是在 Build Analyzer 结果中发现构建时间超时 15% 的情况),则应增加 Java 虚拟化机器 (JVM) 堆大小。 在 gradle.properties 文件中,将限制设置为 4 GB、6 GB 或 8 GB,如以下示例所示:

org.gradle.jvmargs=-Xmx6g

然后测试构建速度是否有提升。确定最佳堆大小最简单的方法是增加限额,然后测试是否有足够的构建速度提升效果。

如果您还使用 JVM 并行垃圾回收器,则整行命令应如下所示:

org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g

您可以通过开启 HeapDumpOnOutOfMemoryError 标记分析 JVM 内存错误。这样,JVM 会在内存耗尽时生成堆转储。

使用非传递 R 类

使用非传递 R 类可为具有多个模块的应用构建更快的 build。这样做有助于确保每个模块的 R 类仅包含对其自身资源的引用,而不会从其依赖项中提取引用,从而帮助防止资源重复。这样可以获得更快的 build,以及避免编译的相应优势。这是 Android Gradle 插件 8.0.0 及更高版本中的默认行为。

从 Android Studio Bumblebee 开始,新项目的非传递 R 类默认处于开启状态。 对于使用早期版本的 Android Studio 创建的项目,请依次前往 Refactor > Migrate to Non-transitive R Classes,将项目更新为使用非传递 R 类。

如需详细了解应用资源和 R 类,请参阅应用资源概览

使用非常量 R 类

您可在应用和测试中使用非常量 R 类字段,以提高 Java 编译的增量并允许进行更精准的资源缩减。 对库而言,R 类字段始终不是常量,因为在为依赖于相应库的应用或测试打包 APK 时,资源会进行编号。 这是 Android Gradle 插件 8.0.0 及更高版本中的默认行为。

停用 Jetifier 标志

由于大多数项目都直接使用 AndroidX 库,因此您可以移除 Jetifier 标志,以便获得更好的构建性能。如需移除 Jetifier 标志,请在 gradle.properties 文件中设置 android.enableJetifier=false

Build Analyzer 可以执行一项检查,确认是否可以安全移除该标记,使您的项目能够具有更好的构建性能,并不再使用未加维护的 Android 支持库。如需详细了解 Build Analyzer,请参阅排查构建性能问题

使用配置缓存(实验性功能)

配置缓存是一项实验性功能,可让 Gradle 记录有关构建任务图的信息,并在后续 build 中重复使用该任务图,而不必再次重新配置整个 build。

如需启用配置缓存,请按以下步骤操作:

  1. 检查所有项目插件是否兼容。

    使用 Build Analyzer 检查项目是否与配置缓存兼容。Build Analyzer 会运行一系列测试 build,以确定是否可以为项目启用该功能。请参阅问题 13490,查看受支持的插件列表。

  2. 将以下代码添加到 gradle.properties 文件:

    org.gradle.unsafe.configuration-cache=true
    
    # Use this flag carefully, in case some of the plugins are not fully compatible.
    org.gradle.unsafe.configuration-cache-problems=warn

启用配置缓存后,当您首次运行项目时,build 输出应该会显示 Calculating task graph as no configuration cache is available for tasks。 在后续运行期间,构建输出应该会显示 Reusing configuration cache

如需详细了解配置缓存,请参阅配置缓存深度解析这篇博文和有关配置缓存的 Gradle 文档。

参考链接