优化构建速度

构建时间太长会拖慢您的开发过程。本页将介绍一些可以帮助您突破构建速度瓶颈的技巧。

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

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

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

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

优化构建配置

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

确保工具已是最新版本

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

创建用于开发的构建变体

为应用发布做准备时所需的许多配置在应用开发过程中都是不必要的。启用不必要的构建流程会减慢您的增量构建和干净构建速度,因此,请配置一个构建变体,使之仅包含开发应用时所需的构建配置。以下代码示例为您的发布版本配置创建了一个“dev”变种和一个“prod”变种:

android {
  ...
  defaultConfig {...}
  buildTypes {...}
  productFlavors {
    // When building a variant that uses this flavor, the following configurations
    // override those in the defaultConfig block.
    dev {
      // To avoid using legacy multidex when building from the command line,
      // set minSdkVersion to 21 or higher. When using Android Studio 2.3 or higher,
      // the build automatically avoids legacy multidex when deploying to a device running
      // API level 21 or higher—regardless of what you set as your minSdkVersion.
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
    }

    prod {
      // If you've configured the defaultConfig block for the release version of
      // your app, you can leave this block empty and Gradle uses configurations in
      // the defaultConfig block instead. You still need to create this flavor.
      // Otherwise, all variants use the "dev" flavor configurations.
    }
  }
}

如果您的构建配置已使用产品变种创建应用的不同版本,您可以使用变种维度将“dev”和“prod”配置与这些变种组合起来。例如,如果您已经配置了“demo”和“full”变种,则可以使用以下示例配置创建组合变种,如“devDemo”和“prodFull”:

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Specifies the flavor dimensions you want to use. The order in which you
  // list each dimension determines its priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.

  flavorDimensions "stage", "mode"

  productFlavors {
    dev {
      dimension "stage"
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
      ...
    }

    prod {
      dimension "stage"
      ...
    }

    demo {
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }
  }
}

单变体项目同步

将项目与构建配置同步,是让 Android Studio 了解项目结构的重要步骤。不过,对于大型项目来说,此过程可能非常耗时。如果您的项目使用了多个 build 变体,那么 Android Studio 只会限制您当前选择的变体,从而优化项目同步操作。

此优化功能默认已在所有项目中启用,在 Android Studio 4.2 及更高版本不再可配置。

如需手动启用此优化功能,您需要使用 Android Studio 3.3 或更高版本与 Android Gradle 插件 3.3.0 或更高版本。依次点击 File > Settings > Experimental > Gradle(在 Mac 上,则依次点击 Android Studio > Preferences > Experimental > Gradle),然后选中 Only sync the active variant 复选框。

注意:此优化功能完全支持包含 Java 和 C++ 语言的项目,部分支持包含 Kotlin 语言的项目。在为包含 Kotlin 内容的项目启用此优化时,Gradle 同步会回退到在内部使用完整的变体。

避免编译不必要的资源

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

android {
  ...
  productFlavors {
    dev {
      ...
      // The following configuration limits the "dev" flavor to using
      // English stringresources and xxhdpi screen-density resources.
      resConfigs "en", "xxhdpi"
    }
    ...
  }
}

对调试 build 停用 Crashlytics

如果您不需要运行 Crashlytics 报告,请按如下方法停用该插件,以提高调试 build 的构建速度:

android {
  ...
  buildTypes {
    debug {
      ext.enableCrashlytics = false
    }
}

此外,您还需要通过更改在应用中初始化对 Fabric 的支持的方式,在运行时为调试 build 停用 Crashlytics 套件,如下所示:

Kotlin

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics.Builder()
        .core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
        .build()
        .also { crashlyticsKit ->
            Fabric.with(this, crashlyticsKit)
        }

Java

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics crashlyticsKit = new Crashlytics.Builder()
    .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
    .build();

Fabric.with(this, crashlyticsKit);

禁止自动生成 build ID

如果您想要将 Crashlytics 用于调试 build,仍可以通过阻止 Crashlytics 在每次构建过程中使用自己的唯一 build ID 更新应用资源,提高增量构建的速度。由于此 build ID 存储在清单引用的资源文件中,因此禁止自动生成 build ID 还可以将 Apply Changes 和 Crashlytics 一起用于您的调试 build。

如需阻止 Crashlytics 自动更新其 build ID,请将以下内容添加到您的 build.gradle 文件中:

android {
  ...
  buildTypes {
    debug {
      ext.alwaysUpdateBuildId = false
    }
}

如需详细了解如何在使用 Crashlytics 时优化您的构建过程,请参阅官方文档

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

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

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

int MILLIS_IN_MINUTE = 1000 * 60
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE

android {
    ...
    defaultConfig {
        // Making either of these two values dynamic in the defaultConfig will
        // require a full APK build and reinstallation because the AndroidManifest.xml
        // must be updated.
        versionCode 1
        versionName "1.0"
        ...
    }

    // The defaultConfig values above are fixed, so your incremental builds don't
    // need to rebuild the manifest (and therefore the whole APK, slowing build times).
    // But for release builds, it's okay. So the following script iterates through
    // all the known variants, finds those that are "release" build types, and
    // changes those properties to something dynamic.
    applicationVariants.all { variant ->
        if (variant.buildType.name == "release") {
            variant.mergedFlavor.versionCode = minutesSinceEpoch;
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
        }
    }
}

使用静态依赖项版本

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 图片时,您可能会注意到设备的 CPU 使用率有小幅上升。通过使用 Android Studio,您可以轻松地将图片转换为 WebP 格式

停用 PNG 处理

如果您无法(或者不想)将 PNG 图像转换为 WebP 格式,仍可以在每次构建应用时停用自动图片压缩,从而提高构建速度。如果您使用的是 Android 插件 3.0.0 或更高版本,默认情况下仅针对“调试”构建类型停用 PNG 处理。如需针对其他构建类型停用此优化,请将以下代码添加到 build.gradle 文件中:

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

// If you're using an older version of the plugin, use the
// following:
//  aaptOptions {
//      cruncherEnabled false
//  }
}

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

使用增量注解处理器

Android Gradle 插件 3.3.0 及更高版本改进了对增量注解处理的支持。因此,如需提高增量构建速度,您应更新 Android Gradle 插件并尽可能仅使用增量注解处理器。

注意:此功能与 Gradle 4.10.1 及更高版本(Gradle 5.1 除外)兼容(请参阅 Gradle 问题 8194)。

首先,参阅下表,了解支持增量注解处理的常见注解处理器。如需更完整的列表,请参阅常见注释处理器中的支持状态。某些注解处理器可能需要额外的步骤才能启用优化,因此请务必阅读每种注解处理器的文档。

此外,如果您在应用中使用 Kotlin,就需要使用 kapt 1.3.30 及更高版本才能在 Kotlin 代码中支持增量注解处理器。请务必阅读有关是否需要手动启用此行为的官方文档。

请注意,如果您必须使用一个或多个不支持增量构建的注释处理器,注释处理将不会是增量的。但是,如果您的项目使用的是 kapt,Java 编译仍然是增量的。

增量注释处理器支持

项目名称注释处理器类名称支持增量处理器的起始版本…
DataBindingandroid.databinding.annotationprocessor.ProcessDataBindingAGP 3.5
Roomandroidx.room.RoomProcessor2.3.0-alpha02

2.20:使用 room.incremental 选项
ButterKnifebutterknife.compiler.ButterKnifeProcessor10.2.0
Glidecom.bumptech.glide.annotation.compiler.GlideAnnotationProcessor4.9.0
Daggerdagger.internal.codegen.ComponentProcessor2.18
Lifecycleandroidx.lifecycle.LifecycleProcessor2.2.0-alpha02
AutoServicecom.google.auto.service.processor.AutoServiceProcessor1.0-rc7
Daggerdagger.android.processor.AndroidProcessor2.18
Realmio.realm.processor.RealmProcessor5.11.0
Lomboklombok.launch.AnnotationProcessorHider$AnnotationProcessor1.16.22
Lomboklombok.launch.AnnotationProcessorHider$ClaimingProcessor1.16.22

配置 JVM 垃圾回收器

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

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

org.gradle.jvmargs=-XX:+UseParallelGC

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

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

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