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

Метрика из сканирования сборки до и после:

Время сократилось с 5.5 минут до 17 секунд!

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

Но сначала!

До начала оптимизации нужно оценить текущую скорость сборки проекта. Gradle предоставляет удобную опцию сканирования для анализа производительности задач. Запустите терминал в Android Studio и выполните следующую команду:

./gradlew assembleDebug --scan

После успешного завершения сборки необходимо принять условия обслуживания, чтобы загрузить результаты сканирования сборки. После завершения публикации в терминале появится ссылка. Откройте ее.

На сайте довольно много опций, однако мы рассмотрим только главные из них.

В разделе summary отображается суммарное количество выполненных задач, а также время их выполнения. В разделе Performance предоставляется более подробная информация об общем времени сборки, как показано на изображении ниже.

Под разделом performance находится панель Settings and suggestions, в которой указаны советы по улучшению скорости сборки. Рассмотрим ее подробнее.

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

Шаг #1: обновление инструментов

Команда Android постоянно совершенствует и развивает систему сборки Android. Таким образом, регулярные простые обновления инструментария помогают значительно улучшить скорость сборки.

На момент этого рефакторинга наш проект был на версии 3.2.1 плагина Gradle для Android Studio (устаревший на несколько версий по сравнению с последним релизом).

По этой ссылке можно скачать версию последнего релиза плагина Gradle.

На момент написания статьи последней версией была 3.4.0.

Однако здесь есть небольшая уловка, которую следует запомнить:

При использовании Gradle 5.0 и версий выше необходимо увеличить размер кучи во избежание ухудшения скорости сборки. Вернемся к этой теме немного позже.

Откройте файл build.gradle высокого уровня, расположенный в root проекта, и добавьте следующую строку в раздел зависимостей:

classpath 'com.android.tools.build:gradle:3.4.0'

Также необходимо обновить URL-адрес дистрибутива в файле свойств wrapper gradle, расположенном в gradle/wrapper/gradle-wrapper.properties.

(Эта ссылка будет доступна на Android Gradle plugin release page)

distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

При использовании в проекте Kotlin возникнет ошибка, если версия плагина Gradle для Kotlin ниже 1.3.0. В таком случае воспользуйтесь prompt IDE для обновления плагина Gradle Kotlin до последней версии (на момент написания этой статьи это была версия 1.3.31).

Теперь снова запустим сборку из терминала, чтобы оценить улучшения.

Шаг #2: обновление конфигураций

Таким образом, время сборки сократилось примерно на 2,5 минуты. Изучив журналы сборки в терминале, находим следующую строку:

С помощью инкрементной компиляции можно избежать компиляции всего набора исходных файлов, поскольку она компилирует только измененные файлы. Из журналов видно, что эта функция не используется. Нам предлагается использовать android.enableSeparateAnnotationProcessing=true, однако, поскольку в проектах используется Kotlin, ‘annotationProcessor’ применять не стоит.

К счастью, в версии Kotlin 1.3.30 добавлена поддержка инкрементной обработки аннотаций.

Теперь:

  1. Меняем конфигурацию annotationProcessor на kapt.
  2. Включаем флаг инкрементальной обработки аннотаций.

Откройте файл build.gradle уровня модуля и добавьте следующую строку в начало файла:

apply plugin: 'kotlin-kapt'

Затем измените все конфигурации annotationProcessor в разделе зависимостей на kapt. Например:

//Before
annotationProcessor 'com.google.dagger:dagger-compiler:2.9'

//After
kapt 'com.google.dagger:dagger-compiler:2.9'

Теперь откройте файл gradle.properties, находящийся в root проекта и добавьте следующую строку:

kapt.incremental.apt=true

Снова запускаем сборку.

Похоже, мы на правильном пути.

Шаг #3: свойства Gradle

Переходим к последней стадии. Помните уловку, на которую мы наткнулись при обновлении версии плагина Gradle? Как оказалось, в более новых версиях Gradle размер кучи уменьшен до 512 МБ во избежание засорения низко производительных устройств.

Откройте файл gradle.properties, расположенный в root проекта и добавьте следующую строку. Не забудьте выбрать размер в соответствии с требованиями и характеристиками устройства.

org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

Также включаем параллельные сборки и настройку по требованию в свойствах.

В конечном итоге файл gradle.properties выглядит следующим образом:

org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

org.gradle.parallel=true

org.gradle.configureondemand=true

kapt.incremental.apt=true
  • org.gradle.parallel — с помощью этого флага Gradle создает модули внутри проекта параллельно, а не последовательно. Рекомендуется использовать только в многомодульном проекте.
  • org.gradle.configureondemand — этот флаг настраивает только необходимые для проекта модули вместо сборки всех модулей сразу.

Теперь посмотрим на метрику скорости сборки:

Получилось. ???

Заключение

Существует еще множество способов оптимизации скорости сборки проекта, таких как использование minSdk 21 вместе с MultiDex, предварительная индексация библиотек, отключение сжатия PNG и т.д.

Однако большинство из этих конфигураций требуют более глубокого понимания системы сборки Android и опыта работы с крупными многомодульными проектами. Шаги, упомянутые выше, привносят значительные улучшения, и их с легкостью могут применить даже младшие разработчики. Надеюсь, эта статья поможет вам в сокращении скорости сборки!


Перевод статьи Prateek Phoenix: How to improve the build speed of your Android projects

Предыдущая статьяKotlin. Коллекции и последовательности
Следующая статьяОтложенная загрузка изображений с помощью Intersection Observer API