Отключите части кода, чтобы ускорить время сборки (Gradle)

У меня есть проект Android, который со временем вырос, и с ростом размера время сборки gradle.

Это было терпимо, пока оно было ниже 65 тыс. Лимитов - около 14 с. Теперь с мультидексом это занимает 36 с.

Так что мой вопрос - есть ли способы "отключить" части кода, которые не используются, чтобы он вернулся за предел в 65 КБ?

Например, отключите Amazon S3 SDK, который вводится через Gradle и имеет n тысяч методов.

Я знаю, что вы можете удалить код с помощью proguard, но это только увеличивает время сборки.

Я счастлив, что он вылетает во время выполнения, когда я открываю части, которые его используют, просто хочу ускорить тестирование.

В тот момент, когда я удаляю amazon из импорта 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);
}

Есть ли что-то подобное, что я мог сделать? Или любым другим способом?

3 ответа

Решение

Можно указать зависимости времени компиляции для каждого типа сборки независимо. Я использую этот метод для включения зависимостей "только для производства" только в сборки выпуска, уменьшая количество методов для сборок отладки.

Например, я включаю Crashlytics только в сборки релизов. Так в build.gradle Я включил зависимость только для моей сборки выпуска (и бета и альфа):

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

Затем я абстрагирую функциональность Crashlytics в класс под названием CrashReportingService, В моем исходном коде отладки этот класс ничего не делает:

/ app / src /debug/java/com/example/services/CrashReportingService.java:

public class CrashReportingService {
    public static void initialise(Context context) {
    }

    public static void logException(Throwable throwable) {
    }
}

И я конкретизирую реализацию в своем исходном коде релиза:

/ app / src /release/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. Вернуться под 65к методов, ура!

Единственный реалистичный способ сделать это (о чем я знаю) - это реорганизовать ваш проект, чтобы ваши пакеты были разделены на отдельные модули. Поэтому у вас будут отдельные файлы сборки Gradle для каждого модуля, но вам нужно будет только перекомпилировать каждый модуль, когда они были затронуты. Вы можете, например, иметь пакет доступа к данным и пакет пользовательского интерфейса. Это кажется довольно естественным расколом.

Я понимаю, что это неутешительный ответ, но проблема, на которую вы жалуетесь, заключается в том, что для ваших зависимостей сборки требуются все лишние ненужные библиотеки и вызовы методов, а не то, что ваш код использует их.

Единственный другой совет, который я могу вам дать, состоит в том, что набор API Google Play содержит десятки тысяч вызовов методов. Если вы можете использовать только те части, которые используете, у вас гораздо больше шансов оказаться ниже предела в 65 КБ.

У меня есть другой вариант. Это также помогает ускорить, но не как ваше требование. Это использует демон.

Если вы используете новую систему сборки Gradle с Android (или Android Studio), вы могли бы понять, что даже самый простой вызов Gradle (например, проект gradle или задачи оценки) довольно медленный. На моем компьютере такие звонки Gradle заняли около восьми секунд. Вы можете уменьшить это время запуска Gradle (на моем компьютере до двух секунд), если вы скажете Gradle использовать демон для сборки. Просто создайте файл с именем gradle.properties в следующем каталоге:

  1. /home/<username>/.gradle/ (Linux)
  2. /Users/<username>/.gradle/ (Mac)
  3. C:\Users\<username>\.gradle (Windows)

Добавьте эту строку в файл:

org.gradle.daemon=true

Отныне Gradle будет использовать демон для сборки, используете ли вы Gradle из командной строки или собираете в Android Studio. Вы также можете поместить файл gradle.properties в корневой каталог вашего проекта и зафиксировать его в своей системе SCM. Но вам придется делать это для каждого проекта (если вы хотите использовать демон в каждом проекте).

Примечание. Если вы ничего не создадите с помощью Gradle в течение некоторого времени (в настоящее время 3 часа), он остановит демона, так что при следующей сборке у вас будет долгое время запуска.


Как Gradle Daemon делает сборки быстрее?

Gradle Daemon - это долгоживущий процесс сборки. Между сборками он праздно ждет следующей сборки. Это имеет очевидное преимущество: требуется, чтобы Gradle загружался в память только один раз для нескольких сборок, а не один раз для каждой сборки. Само по себе это значительная оптимизация производительности, но это еще не все.

Важной частью истории современной производительности JVM является оптимизация кода во время выполнения. Например, HotSpot (реализация JVM, предоставляемая Oracle и используемая в качестве основы OpenJDK) применяет оптимизацию к коду во время его работы. Оптимизация является прогрессивной, а не мгновенной. Таким образом, код постепенно оптимизируется во время выполнения, что означает, что последующие сборки могут быть быстрее исключительно благодаря этому процессу оптимизации.

Эксперименты с HotSpot показали, что для стабилизации требуется от 5 до 10 сборок. Разница в воспринимаемом времени сборки между первой сборкой и десятой для демона может быть весьма существенной.

Демон также позволяет более эффективно кэшировать память во всех сборках. Например, классы, необходимые для сборки (например, плагины, сценарии сборки), могут храниться в памяти между сборками. Аналогично, Gradle может поддерживать в памяти кэши данных сборки, таких как хеши входов и выходов задач, используемых для инкрементного построения.

Некоторые другие способы ускорить процесс

  1. Как ускорить ваш Gradle Build от 90 до 8 минут?
  2. Как оптимизировать производительность сборки Gradle с точки зрения продолжительности сборки и использования оперативной памяти?
Другие вопросы по тегам