4

我有一个随着时间增长的 Android 项目,随着规模的增长,gradle 构建时间也随之增长。

当它低于 65k 限制时,它是可以忍受的——大约14 秒。现在使用 multidex 需要36s

所以我的问题是 - 有没有办法“关闭”部分未使用的代码,使其回到 65k 限制之下?

例如,关闭通过 gradle 引入并具有数千种方法的 amazon s3 sdk。

我知道您可以使用 proguard 剥离代码,但这只会增加构建时间。

当我打开使用它的部件时,我很高兴它在运行时崩溃,只是想让测试更快。

在我从 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);
}

我能做这样的事情吗?还是有什么其他方式?

4

3 回答 3

3

这样做的唯一现实方法(我知道)是重构您的项目,以便将您的包拆分为单独的模块。因此,您将为每个模块拥有单独的 gradle 构建文件,但只需在每个模块被触及时重新编译它们。例如,您可以拥有一个数据访问包和一个 UI 包。这似乎是一个很自然的分裂。

我意识到这是一个令人失望的答案,但您抱怨的问题是您的构建依赖项需要所有那些额外的不必要的库和方法调用:而不是您的代码使用它们。

我能给你的唯一提示是 Google Play API 工具包有数以万计的方法调用。如果您只能使用您正在使用的部分,那么您更有可能低于 65k 限制。

于 2016-04-26T00:19:42.830 回答
1

可以独立地为每个构建类型指定编译时依赖项。我使用此方法仅在发布版本中包含“仅生产”依赖项,从而减少调试版本的方法数。

例如,我只在发布版本中包含 Crashlytics。因此,build.gradle我只包含我的发布版本(以及 beta 和 alpha)的依赖项:

releaseCompile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
    transitive = true;
}

然后我将 Crashlytics 的功能抽象到一个名为CrashReportingService. 在我的调试源代码中,这个类什么都不做:

/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 方法下,万岁!

于 2016-04-30T20:07:23.647 回答
0

我有另一个选择。这也有助于加快速度,但不能满足您的需求。那是用

如果您将新的 Gradle 构建系统与 Android(或 Android Studio)一起使用,您可能已经意识到,即使是最简单的 Gradle 调用(例如 gradle 项目或成绩任务)也非常慢。在我的电脑上,这种 Gradle 调用大约需要 8 秒钟。如果您告诉 Gradle 使用守护程序进行构建,您可以减少 Gradle 的启动时间(在我的计算机上减少到两秒)。gradle.properties只需在以下目录中创建一个名为的文件:

  1. /home/<username>/.gradle/(Linux)
  2. /Users/<username>/.gradle/(苹果电脑)
  3. C:\Users\<username>\.gradle(视窗)

将此行添加到文件中:

org.gradle.daemon=true

从现在开始,Gradle 将使用守护进程来构建,无论您是从命令行使用 Gradle 还是在 Android Studio 中构建。您还可以将 gradle.properties 文件放在项目的根目录中,并将其提交到您的 SCM 系统。但是您必须为每个项目执行此操作(如果您想在每个项目中使用守护程序)。

注意:如果您有一段时间(目前是 3 小时)没有使用 Gradle 构建任何东西,它将停止守护进程,这样您在下一次构建时会遇到很长的启动时间。


Gradle Daemon 如何使构建更快?

Gradle 守护进程是一个长期存在的构建过程。在构建之间,它空闲地等待下一个构建。这有一个明显的好处,即多个构建只需要一次将 Gradle 加载到内存中,而不是每个构建一次。这本身就是一个重要的性能优化,但这不是它停止的地方。

现代 JVM 性能的一个重要部分是运行时代码优化。例如,HotSpot(Oracle 提供的 JVM 实现,用作 OpenJDK 的基础)在代码运行时对其进行优化。优化是渐进的而不是瞬时的。也就是说,代码在执行过程中逐渐优化,这意味着后续构建可以更快地纯粹由于这个优化过程。

使用 HotSpot 的实验表明,优化需要 5 到 10 次构建才能稳定。守护进程的第一次构建和第十次构建之间的感知构建时间差异可能非常显着。

守护进程还允许更有效地跨构建进行内存缓存。例如,构建所需的类(例如插件、构建脚本)可以在构建之间保存在内存中。同样,Gradle 可以维护构建数据的内存缓存,例如任务输入和输出的哈希值,用于增量构建。

其他一些加快进程的方法

  1. 如何将 Gradle 构建时间从 90 分钟缩短到 8 分钟?
  2. 如何针对构建持续时间和 RAM 使用优化 gradle 构建性能?
于 2016-04-28T17:37:06.397 回答