构建 优化构建速度 Optimize build speed


优化您的构建速度

Optimize your build speed

长构建时间会减慢您的开发过程,因此本页面将介绍一些可以帮助您解决构建速度瓶颈[bottlenecks]的技巧[techniques]。

改进您的构建速度的一般过程如下所示:

  • 采取一些可以立即为大多数 Android Studio 项目带来好处[benefit]的措施,优化您的构建配置
  • 分析[Profile]您的构建,确定并诊断[identify and diagnose]一些对您的项目或工作站来说比较棘手的瓶颈[trickier bottlenecks]。

在开发您的应用时,如果可以,您应部署到[deploy to]正在运行 Android 7.0(API 级别 24)或更高版本的设备。较新版本的 Android 平台实现更好的机制[mechanics]来向您的应用推送更新[pushing updates],例如 Android Runtime (ART) 以及对 multiple DEX files 的原生支持。

注:在您的首个干净构建[clean build]后,您可能会注意到后续[subsequent]构建(干净和增量[incremental])的执行速度明显加快(即使没有使用本页介绍的任何优化措施,也是如此)。这是因为 Gradle 后台程序[daemon]有一个提升性能[increasing performance]的“预热”期[warm-up period] - 与其他 JVM 进程类似。
1
 
1
注:在您的首个干净构建[clean build]后,您可能会注意到后续[subsequent]构建(干净和增量[incremental])的执行速度明显加快(即使没有使用本页介绍的任何优化措施,也是如此)。这是因为 Gradle 后台程序[daemon]有一个提升性能[increasing performance]的“预热”期[warm-up period] - 与其他 JVM 进程类似。

优化您的构建配置

Optimize your build configuration

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

保持工具处于最新状态

Keep your tools up to date

Android 工具几乎在每一次更新中都会获得构建优化和新功能,本页介绍的一些 tips 假设您正在使用最新版本。要充分利用最新优化,请保持以下工具处于最新状态:

为开发创建构建变体

Create a build variant for development

准备发布应用时需要的许多配置在开发应用时都不需要。启用不必要的构建进程会减慢您的增量构建和干净构建速度,因此,在开发您的应用期间,配置一个构建变体,使之仅包含您需要的构建配置。下面的示例将为您的发布版本配置创建一个“开发”风味和一个“生产”风味:

android {
  defaultConfig {...}
  buildTypes {...}
  productFlavors {
    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. */
    }
  }
}
16
 
1
android {
2
  defaultConfig {...}
3
  buildTypes {...}
4
  productFlavors {
5
    dev {
6
/** 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. */
7
      minSdkVersion 21
8
      versionNameSuffix "-dev"
9
      applicationIdSuffix '.dev'
10
    }
11
12
    prod {
13
/** 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. */
14
    }
15
  }
16
}

如果您的构建配置已使用产品风味创建不同版本的应用,您可以使用风味维度,将“开发”和“生产”配置与这些风味组合。例如,如果您已配置“演示”和“完整”风味,您可以使用下面的示例配置创建组合风味,例如“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"
    }
  }
}
28
 
1
android {
2
  defaultConfig {...}
3
  buildTypes {...}
4
5
/** 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. */
6
  flavorDimensions "stage", "mode"
7
8
  productFlavors {
9
    dev {
10
      dimension "stage"
11
      minSdkVersion 21
12
      versionNameSuffix "-dev"
13
      applicationIdSuffix '.dev'
14
    }
15
16
    prod {
17
      dimension "stage"
18
    }
19
20
    demo {
21
      dimension "mode"
22
    }
23
24
    full {
25
      dimension "mode"
26
    }
27
  }
28
}

避免编译不必要的资源

Avoid compiling unnecessary resources

避免编译和打包您没有测试的资源(例如其他语言本地化和屏幕密度资源[additional language localizations and screen-density resources])。为此,您可以仅为“开发”风味指定一个语言资源和屏幕密度,如下面的示例中所示:

android {
  productFlavors {
    dev {
      // The following configuration limits the "dev" flavor to using English stringresources and xxhdpi screen-density resources.
      resConfigs "en", "xxhdpi"
    }
    ...
  }
}
9
 
1
android {
2
  productFlavors {
3
    dev {
4
      // The following configuration limits the "dev" flavor to using English stringresources and xxhdpi screen-density resources.
5
      resConfigs "en", "xxhdpi"
6
    }
7
    ...
8
  }
9
}

为您的调试构建停用 Crashlytics

Disable Crashlytics for your debug builds

如果您不需要运行 Crashlytics report,请按以下步骤操作来停用插件,以便加快您的调试构建的速度:

android {
  buildTypes {
    debug {
      ext.enableCrashlytics = false //停用 Crashlytics
    }
}
6
 
1
android {
2
  buildTypes {
3
    debug {
4
      ext.enableCrashlytics = false //停用 Crashlytics
5
    }
6
}

您也需要更改在应用中为 Fabric 初始化支持的方式,在运行时为调试构建停用 Crashlytics 套件,如下所示:

// 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);
5
 
1
// Initializes Fabric for builds that don't use the debug build type.
2
Crashlytics crashlyticsKit = new Crashlytics.Builder()
3
    .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
4
    .build();
5
Fabric.with(this, crashlyticsKit);

如果您想要将 Crashlytics 与调试构建结合使用,仍可以通过以下方式来加快增量构建的速度:在每个构建期间阻止 Crashlytics 使用它自己的独特构建 ID 更新应用资源。要阻止 Crashlytics 不断更新其构建 ID,请将以下代码添加到您的 build.gradle 文件中:

android {
  buildTypes {
    debug {
      ext.alwaysUpdateBuildId = false //阻止 Crashlytics 不断更新其构建 ID,加快增量构建的速度
    }
}
6
 
1
android {
2
  buildTypes {
3
    debug {
4
      ext.alwaysUpdateBuildId = false //阻止 Crashlytics 不断更新其构建 ID,加快增量构建的速度
5
    }
6
}

如需了解有关在使用 Crashlytics 时优化您的构建的详细信息,请阅读官方文档

使用静态构建配置值

Use static build config values with your debug build

始终为进入 manifest 文件的属性使用静态/硬编码[static/hard-coded]值,或者为您的调试构建类型使用资源文件。如果您的 manifest 文件或应用资源中的值需要随着每一个构建更新,Instant Run 将无法执行代码交换 - 它必须构建和安装新的 APK。

例如,在您每次想要运行更改时,使用动态版本代码、版本名称、资源或任何其他可以更改 manifest 文件的构建逻辑都需要一个完整的 APK 构建 - 即使实际更改仅需要一个热交换,也是如此。如果您的构建配置需要此类动态属性,那么将其隔离到您的发布构建变体中并让值对您的调试构建保持静态,如下面的 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 (which is not supported by Instant Run). */
        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;
        }
    }
}
18
 
1
int MILLIS_IN_MINUTE = 1000 * 60
2
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE  //分钟
3
4
android {
5
    defaultConfig {
6
/** 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 (which is not supported by Instant Run). */
7
        versionCode 1
8
        versionName "1.0"
9
    }
10
11
/** 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. */
12
    applicationVariants.all { variant ->
13
        if (variant.buildType.name == "release") {
14
            variant.mergedFlavor.versionCode = minutesSinceEpoch;
15
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
16
        }
17
    }
18
}

使用静态依赖项版本

Use static dependency versions

 build.gradle 文件中声明依赖项时,您应当避免在结尾将版本号与加号一起使用,例如 'com.android.tools.build:gradle:2.+'。使用动态版本号可能导致意外版本更新和难以解析版本差异[difficulty resolving version differences],并因 Gradle 检查有无更新而减慢构建速度。您应改为使用静态/硬编码版本号。

启用离线模式

Enable offline mode

如果您的网络连接速度比较慢,那么在 Gradle 尝试使用网络资源解析依赖项时,您的构建时间可能会延长。您可以指示 Gradle 仅使用它已经缓存到本地的工件来避免使用网络资源。

要在使用 Android Studio 构建时离线使用 Gradle,请执行以下操作:

点击 File > Settings,打开 Preferences 窗口,在左侧窗格中,点击 Build, Execution, Deployment > Gradle,勾选 Offline work 复选框,点击 Apply 或 OK。
1
 
1
点击 File > Settings,打开 Preferences 窗口,在左侧窗格中,点击 Build, Execution, Deployment > Gradle,勾选 Offline work 复选框,点击 Apply  OK。

如果您正在从命令行构建,请传递 --offline 选项。

启用按需配置

Enable configuration on demand

为了让 Gradle 准确了解如何构建您的应用,构建系统会在每个构建前在项目中配置所有模块[configures all modules in your project]以及这些模块的依赖项(即使您正在构建和测试一个模块,也是如此)。这会减慢大型多模块项目的构建进程。要指示 Gradle 仅配置您想要构建的模块,请按以下步骤操作,启用按需配置

点击 File > Settings,打开 Preferences 窗口,在左侧窗格中,点击 Build, Execution, Deployment > Compiler,勾选 Configure on demand 复选框,点击 Apply 或 OK。
1
 
1
点击 File > Settings,打开 Preferences 窗口,在左侧窗格中,点击 Build, Execution, Deployment > Compiler,勾选 Configure on demand 复选框,点击 Apply  OK。
Gradle 4.6 users: If you're using either Android Plugin for Gradle 3.0.1 or 3.1.0 with Gradle 4.6, you should disable configuration on demand to avoid some unpredictable不可预料的 build errors. This issue should be fixed in a future version of the plugin.
1
 
1
Gradle 4.6 users: If you're using either Android Plugin for Gradle 3.0.1 or 3.1.0 with Gradle 4.6, you should disable configuration on demand to avoid some unpredictable不可预料的 build errors. This issue should be fixed in a future version of the plugin.

创建库模块

Create library modules

在应用中查找您可以转换成 Android 库模块的代码。通过这种方式将您的代码模块化[Modularizing]可以让构建系统仅编译您修改的模块,并缓存这些输出以用于未来构建。这种方式也会让按需配置[configuration on demand]和并行项目执行[parallel project execution]更有效(如果您启用这些功能)。

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

Create tasks for custom build logic

在您创建构建分析[create a build profile]后,如果分析显示构建时间中相当大的一部分用在了“配置项目”阶段[Configuring Projects phase],请检查 build.gradle 脚本并查找您可以添加到自定义 Gradle 任务中的代码。将某个构建逻辑移动到任务中后,它仅会在需要时运行,可以为后续构建缓存结果,并且该构建逻辑将有资格并行运行[becomes eligible to run in parallel](如果您启用并行项目执行)。要了解详情,请阅读官方 Gradle 文档

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

将图像转换成 WebP

Convert images to WebP

WebP 是一种既可以提供有损压缩[lossy compression](像 JPEG 一样)也可以提供透明度[transparency](像 PNG 一样)的图片文件格式,不过与 JPEG 或 PNG 相比,这种格式可以提供更好的压缩。降低图片文件大小可以加快构建的速度(无需执行构建时压缩),尤其是在您的应用使用大量图像资源时,更是如此。不过,在对 WebP 图像进行解压缩时,您可能会注意到设备的 CPU 使用率有小幅上升。使用 Android Studio 时,您可以轻松地将图像转换成 WebP

停用 PNG 处理

Disable PNG crunching

如果您无法(或者不想)将 PNG 图像转换成 WebP,仍可以通过在每次构建应用时停用自动图像压缩的方式加快构建速度。

If you're using Android plugin 3.0.0 or higher, PNG crunching is disabled by default for only the "debug" build type. To disable this optimization for other build types, add the following to your build.gradle file:

android {
    buildTypes {
        release {
            crunchPngs false  // Disables PNG crunching for the release build type.
        }
    }
}
7
 
1
android {
2
    buildTypes {
3
        release {
4
            crunchPngs false  // Disables PNG crunching for the release build type.
5
        }
6
    }
7
}

If you're using an older version of the plugin, use the following:

android {
  aaptOptions {
      cruncherEnabled false
  }
}
5
 
1
android {
2
  aaptOptions {
3
      cruncherEnabled false
4
  }
5
}

由于构建类型[备注:这个可是是旧的文档,新版本不是已经可以在buildTypes中修改此属性了吗?]或产品风味不定义此属性,在构建发布版本的应用时,您需要将此属性手动设置为 true

启用 Instant Run

Enable Instant Run

Instant Run 可以在不构建新 APK 的情况下(某些情况下,甚至不需要重启当前 Activity)推送特定代码和资源更改[pushing certain code and resource changes],从而显著缩短[significantly reduces]更新您的应用所需的时间。在对您的应用进行更改后,点击 Apply Changes  以使用 Instant Run,此功能会在您执行以下操作时默认启用:

  • 使用 debug 构建变体构建您的应用。
  • 使用 Android Plugin for Gradle 2.3.0 或更高版本。
  • 在应用的模块级 build.gradle 文件中将 minSdkVersion 设置为 15 或更高。
  • 点击 Run ,将您的应用部署到运行 Android 5.0(API 级别 21)及更高版本的设备上。

如果满足这些要求后您在工具栏中没有看到 Apply Changes  按钮,请按以下步骤操作,确保未在 IDE 设置中停用 Instant Run:

打开 Settings 或者 Preferences 对话框,导航至 Build, Execution, Deployment > Instant Run,确保勾选 Enable Instant Run。
1
 
1
打开 Settings 或者 Preferences 对话框,导航至 Build, Execution, Deployment > Instant Run,确保勾选 Enable Instant Run。

启用构建缓存

Enable the build cache

构建缓存可以存储 Android Plugin for Gradle 在构建您的项目时生成的特定输出(例如未打包的[unpackaged] AAR 和 pre-dexed 远程依赖项)。使用缓存时,您的干净构建将显著加快,因为构建系统在后续构建期间可以直接重用这些缓存文件,而不用重新创建它们。

使用 Android 插件 2.3.0 及更高版本的新项目在默认情况下会启用构建缓存(除非您明确停用构建缓存)。要了解详情,请阅读使用构建缓存加快干净构建的速度

停用注解处理器

Disable annotation processors

使用注解处理器时,增量 Java 编译处于停用状态。如果可以,请尝试避免使用注解处理器,以便在不同构建之间仅编译您修改的类。


分析您的构建

Profile your build

较大的项目或者实现许多自定义构建逻辑的项目可能要求您深入查看构建进程才能找到瓶颈。为此,您可以分析 Gradle 执行构建生命周期的每个阶段和每个构建任务所需的时间。例如,如果您的构建分析显示 Gradle 在配置项目时花费了过多的时间,可能表明您需要将自定义构建逻辑移出配置阶段。此外,如果 mergeDevDebugResources 任务占用了大量构建时间,则表明您还需要将图像转换成 WebP 或者停用 PNG 处理

使用分析来加快构建速度一般涉及在启用分析的情况下运行构建,对构建配置进行一些调整,以及进行更多分析来观察更改的结果。
Using profiling to improve your build speed typically involves running your build with profiling enabled, making some tweaks to your build configuration, and profiling some more to observe the results of your changes.

要生成和查看构建分析,请执行以下步骤:

1、在 Android Studio 中打开您的项目后,选择   View > Tool Windows > Terminal   以在项目的根目录下打开命令行。
2、输入以下命令来执行干净构建。在分析构建时,您应当在分析的每个构建之间执行干净构建,因为 Gradle 会在任务(例如源代码)的输入未发生变化时跳过任务。因此,没有输入更改的第二个构建总会以更快的速度运行,因为任务不会重复运行。在不同构建之间运行   clean   任务可以确保您分析完整的构建进程。
gradlew clean // On Mac or Linux, run the Gradle wrapper using "./gradlew".
x
 
1
gradlew clean // On Mac or Linux, run the Gradle wrapper using "./gradlew".
3、使用以下标志为您的产品风味之一(例如“开发”风味)执行调试构建:
gradlew --profile --recompile-scripts --offline --rerun-tasks assembleFlavorDebug
x
 
1
gradlew --profile --recompile-scripts --offline --rerun-tasks assembleFlavorDebug
    • --profile:启用分析。
    • --recompile-scripts:在绕过缓存时强制重新编译脚本。
    • --offline:禁止 Gradle 提取在线依赖项。这样可以确保 Gradle 在尝试更新依赖项时引起的任何延迟都不会干扰您的分析数据。您应当已将项目构建一次,以便确保 Gradle 已经下载和缓存您的依赖项。
    • --rerun-tasks:强制 Gradle 重新运行所有任务并忽略任何任务优化。
    • assembleFlavorDebug:要执行的的构建变体
          4、在构建完成后,请使用   Project   窗口导航至   project-root /build/reports/profile/   目录。
          5、右键点击  profile- timestamp .html 文件,然后选择 Open in Browser > Default。您可以检查报告中的每个标签来了解构建,例如,Task Execution 标签显示了 Gradle 执行每个构建任务花费的时间。
           

          6、可选:在对您的项目或构建配置进行任何更改之前[Before making any changes to your project or build configuration],请重复第 3 步中的命令,但请忽略 --rerun-tasks 标志。由于 Gradle 会尝试通过不重复执行输入未发生变化的任务来节省时间[attempts to save time by not re-executing tasks whose inputs haven't changed](这些任务在报告的 Task Execution 标签中标记为 UP-TO-DATE),您可以确定哪些任务在不必要的时间执行了工作[you can identify which tasks are performing work when they shouldn't be]。例如,如果 :app:processDevUniversalDebugManifest 未标记为 UP-TO-DATE,则可能说明您的构建配置会随着每个构建动态更新 manifest。不过,有些任务(例如 :app:checkDevDebugManifest)需要在每个构建期间始终运行。


          现在,您已经有了一个构建分析报告,可以通过检查报告每个标签中的信息来寻找优化机会[looking for optimization opportunities by inspecting the information in each tab of the report]。有些构建设置要求实验[experimentation],因为它们的好处在项目与工作站之间可能有所不同[the benefits may differ between projects and workstations]。例如,包含大型代码库的项目可能会受益于 using ProGuard 移除未使用的代码和压缩 APK 大小。不过,较小的项目则可能从完全停用 ProGuard 中受益。此外,增加 Gradle 堆大小可能会降低小内存机器的性能[negatively impact performance on low-memory machines]。

          在对您的构建配置进行更改后,请重复上述步骤并生成新的构建分析来观察更改的结果。

          提示:如需更强大的分析工具,请考虑使用 Gradle 的开放源代码分析器



          2018-7-23

          猜你喜欢

          转载自www.cnblogs.com/baiqiantao/p/9354468.html