关闭部分代码以加快构建时间 (Gradle)
Turn off parts of code to speed up build times (Gradle)
我有一个 Android 项目,它随着时间的推移而增长,并且随着规模的增长,gradle 构建时间。
在 65k 限制以下时是可以忍受的 - 大约 14s。
现在使用 multidex 需要 36s.
所以我的问题是 - 有没有什么方法可以 "turn off" 未使用的代码部分,使其回到 65k 限制以下?
例如关闭通过gradle引入的amazon s3 sdk,它有上千种方法。
我知道您可以使用混淆器剥离代码,但这只会增加构建时间。
当我打开使用它的部分时,我很高兴它在运行时崩溃,只是想让测试更快。
当我从 gradle 进口中删除亚马逊时,我显然得到了这个:
Error:(24, 26) error: package com.amazonaws.auth does not exist
有没有办法以某种方式忽略错误?我知道在 Picasso 中,它有一个运行时检查,看看你是否有 OkHttp,如果没有 - 使用标准网络。
static Downloader createDefaultDownloader(Context context) {
if (SDK_INT >= GINGERBREAD) {
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException ignored) {}
}
return new UrlConnectionDownloader(context);
}
我可以做这样的事情吗?或者其他方式?
唯一现实的方法(据我所知)是重构您的项目,以便将您的包拆分为单独的模块。因此,您将为每个模块创建单独的 gradle 构建文件,但只需在触摸每个模块时重新编译它们。例如,您可以有一个数据访问包和一个 UI 包。这似乎是一个很自然的分裂。
我知道这是一个令人失望的答案,但您抱怨的问题是您的构建依赖项需要所有那些额外的不必要的库和方法调用:而不是您的代码使用它们。
我能给你的唯一其他提示是 Google Play API 工具包有数以万计的方法调用。如果您只能使用您正在使用的部分,那么您更有可能低于 65k 限制。
I have got another option. That also helps to speed up but not as your
demand. That is using demon.
如果您将新的 Gradle 构建系统与 Android(或 Android Studio)一起使用,您可能已经意识到,即使是最简单的 Gradle 调用(例如 gradle project or grade tasks) 很慢。在我的电脑上,这种 Gradle 调用大约需要八秒钟。如果你告诉 Gradle 使用守护进程来构建,你可以减少 Gradle 的启动时间(在我的电脑上减少到两秒)。只需在以下目录中创建一个名为 gradle.properties
的文件:
/home/<username>/.gradle/
(Linux)
/Users/<username>/.gradle/
(Mac)
C:\Users\<username>\.gradle
(Windows)
将此行添加到文件中:
org.gradle.daemon=true
从现在开始,Gradle 将使用守护进程进行构建,无论您是从命令行使用 Gradle 还是在 Android Studio 中构建。您也可以将 gradle.properties 文件放在项目的根目录下,然后将其提交到您的 SCM 系统。但是你必须对每个项目都这样做(如果你想在每个项目中使用守护进程)。
Note: If you don’t build anything with Gradle for some time (currently
3 hours), it will stop the daemon, so that you will experience a long
start-up time at the next build.
How does the Gradle Daemon make builds faster?
Gradle 守护进程是一个长期存在的构建过程。在构建之间,它空闲地等待下一个构建。这有一个明显的好处,即只需要 Gradle 为多个构建加载到内存中一次,而不是每次构建一次。这本身就是一个重要的性能优化,但它不止于此。
现代 JVM 性能的重要组成部分是运行时代码优化。例如,HotSpot(Oracle 提供的 JVM 实现,用作 OpenJDK 的基础)在 运行 时对代码进行优化。优化是渐进的而不是即时的。也就是说,代码在执行期间逐渐优化,这意味着后续构建可以纯粹由于此优化过程而更快。
Experiments with HotSpot have shown that it takes somewhere between 5
and 10 builds for optimization to stabilize. The difference in
perceived build time between the first build and the 10th for a Daemon
can be quite dramatic.
守护进程还允许更有效地跨构建进行内存缓存。例如,构建所需的 类(例如插件、构建脚本)可以在构建之间保存在内存中。同样,Gradle 可以维护构建数据的内存缓存,例如任务输入和输出的哈希值,用于增量构建。
一些其他加快进程的方法
- How to Speed Up Your Gradle Build From 90 to 8 Minutes?
- How to optimize gradle build performance regarding build duration and RAM usage?
可以为每个构建类型单独指定编译时依赖项。我使用此方法仅在发布版本中包含 "production-only" 依赖项,减少调试版本的方法数。
例如,我只在发布版本中包含 Crashlytics。因此,在 build.gradle
中,我仅包含对 release 构建(以及 beta 和 alpha)的依赖项:
releaseCompile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
transitive = true;
}
然后我将 Crashlytics 的功能抽象为一个名为 CrashReportingService
的 class。在我的调试源代码中,这个 class 什么都不做:
/app/src/调试/java/com/example/services/CrashReportingService.java:
public class CrashReportingService {
public static void initialise(Context context) {
}
public static void logException(Throwable throwable) {
}
}
我在发布源代码中充实了实现:
/app/src/发布/java/com/example/services/CrashReportingService.java
public class CrashReportingService {
public static void initialise(Context context) {
Fabric.with(context, new Crashlytics());
}
public static void logException(Throwable throwable) {
Crashlytics.getInstance().core.logException(throwable);
}
}
Crashlytics 现在只包含在发布版本中,在我的调试版本中没有引用 Crashlytics。回到 65k 方法,万岁!
我有一个 Android 项目,它随着时间的推移而增长,并且随着规模的增长,gradle 构建时间。
在 65k 限制以下时是可以忍受的 - 大约 14s。 现在使用 multidex 需要 36s.
所以我的问题是 - 有没有什么方法可以 "turn off" 未使用的代码部分,使其回到 65k 限制以下?
例如关闭通过gradle引入的amazon s3 sdk,它有上千种方法。
我知道您可以使用混淆器剥离代码,但这只会增加构建时间。
当我打开使用它的部分时,我很高兴它在运行时崩溃,只是想让测试更快。
当我从 gradle 进口中删除亚马逊时,我显然得到了这个:
Error:(24, 26) error: package com.amazonaws.auth does not exist
有没有办法以某种方式忽略错误?我知道在 Picasso 中,它有一个运行时检查,看看你是否有 OkHttp,如果没有 - 使用标准网络。
static Downloader createDefaultDownloader(Context context) {
if (SDK_INT >= GINGERBREAD) {
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException ignored) {}
}
return new UrlConnectionDownloader(context);
}
我可以做这样的事情吗?或者其他方式?
唯一现实的方法(据我所知)是重构您的项目,以便将您的包拆分为单独的模块。因此,您将为每个模块创建单独的 gradle 构建文件,但只需在触摸每个模块时重新编译它们。例如,您可以有一个数据访问包和一个 UI 包。这似乎是一个很自然的分裂。
我知道这是一个令人失望的答案,但您抱怨的问题是您的构建依赖项需要所有那些额外的不必要的库和方法调用:而不是您的代码使用它们。
我能给你的唯一其他提示是 Google Play API 工具包有数以万计的方法调用。如果您只能使用您正在使用的部分,那么您更有可能低于 65k 限制。
I have got another option. That also helps to speed up but not as your demand. That is using demon.
如果您将新的 Gradle 构建系统与 Android(或 Android Studio)一起使用,您可能已经意识到,即使是最简单的 Gradle 调用(例如 gradle project or grade tasks) 很慢。在我的电脑上,这种 Gradle 调用大约需要八秒钟。如果你告诉 Gradle 使用守护进程来构建,你可以减少 Gradle 的启动时间(在我的电脑上减少到两秒)。只需在以下目录中创建一个名为 gradle.properties
的文件:
/home/<username>/.gradle/
(Linux)/Users/<username>/.gradle/
(Mac)C:\Users\<username>\.gradle
(Windows)
将此行添加到文件中:
org.gradle.daemon=true
从现在开始,Gradle 将使用守护进程进行构建,无论您是从命令行使用 Gradle 还是在 Android Studio 中构建。您也可以将 gradle.properties 文件放在项目的根目录下,然后将其提交到您的 SCM 系统。但是你必须对每个项目都这样做(如果你想在每个项目中使用守护进程)。
Note: If you don’t build anything with Gradle for some time (currently 3 hours), it will stop the daemon, so that you will experience a long start-up time at the next build.
How does the Gradle Daemon make builds faster?
Gradle 守护进程是一个长期存在的构建过程。在构建之间,它空闲地等待下一个构建。这有一个明显的好处,即只需要 Gradle 为多个构建加载到内存中一次,而不是每次构建一次。这本身就是一个重要的性能优化,但它不止于此。
现代 JVM 性能的重要组成部分是运行时代码优化。例如,HotSpot(Oracle 提供的 JVM 实现,用作 OpenJDK 的基础)在 运行 时对代码进行优化。优化是渐进的而不是即时的。也就是说,代码在执行期间逐渐优化,这意味着后续构建可以纯粹由于此优化过程而更快。
Experiments with HotSpot have shown that it takes somewhere between 5 and 10 builds for optimization to stabilize. The difference in perceived build time between the first build and the 10th for a Daemon can be quite dramatic.
守护进程还允许更有效地跨构建进行内存缓存。例如,构建所需的 类(例如插件、构建脚本)可以在构建之间保存在内存中。同样,Gradle 可以维护构建数据的内存缓存,例如任务输入和输出的哈希值,用于增量构建。
一些其他加快进程的方法
- How to Speed Up Your Gradle Build From 90 to 8 Minutes?
- How to optimize gradle build performance regarding build duration and RAM usage?
可以为每个构建类型单独指定编译时依赖项。我使用此方法仅在发布版本中包含 "production-only" 依赖项,减少调试版本的方法数。
例如,我只在发布版本中包含 Crashlytics。因此,在 build.gradle
中,我仅包含对 release 构建(以及 beta 和 alpha)的依赖项:
releaseCompile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
transitive = true;
}
然后我将 Crashlytics 的功能抽象为一个名为 CrashReportingService
的 class。在我的调试源代码中,这个 class 什么都不做:
/app/src/调试/java/com/example/services/CrashReportingService.java:
public class CrashReportingService {
public static void initialise(Context context) {
}
public static void logException(Throwable throwable) {
}
}
我在发布源代码中充实了实现:
/app/src/发布/java/com/example/services/CrashReportingService.java
public class CrashReportingService {
public static void initialise(Context context) {
Fabric.with(context, new Crashlytics());
}
public static void logException(Throwable throwable) {
Crashlytics.getInstance().core.logException(throwable);
}
}
Crashlytics 现在只包含在发布版本中,在我的调试版本中没有引用 Crashlytics。回到 65k 方法,万岁!