Привет, Хабр! Настало время, когда можно сказать, что «new build system» Gradle является стандартом отрасли Android-разработки. Инструмент сделан настолько просто и удобно, что большинство разработчиков не испытает трудностей, даже не зная, как он устроен, и какие дополнительные возможности в нём есть — возникающие проблемы легко решаются с помощью 5 минут на StackOverflow, путем копирования «магического кода» в конфигурационные файлы. Возможно, в том числе из-за этого не все разработчики изучают Gradle детально и не знают о многих его полезных возможностях, которые существенно облегчают жизнь.
Речь пойдет о:
Время сборки напрямую влияет на скорость разработки. Тесты показывают, что каждая из версий, начиная с Gradle 2.0, становилась медленнее предыдущей. Однако затем разработчики исправились и хорошенько поработали над быстродействием в Gradle 2.4.
1. Поэтому первым делом следует убедиться, что вы используете актуальную версию Gradle 2.4+
2. Затем, удостоверившись, что вы пытаетесь ускорить свою рабочую машину, а не сервер CI, включить Gradle демон — это даст значительный прирост в скорости сборки.
Строки конфигурации стоит добавлять в файл ./%project%/gradle.properties, если вы хотите распространить конфигурацию на все проекты, то необходимо конфигурировать файл, лежащий в домашней папке вашего пользователя
~/.gradle/gradle.properties
3. После чего, проверив что модули вашего проекта не используют друг-друга как зависимости, тем самым создавая перекрёстные ссылки, можно смело включать режим параллельного выполнения, что также ускорит скорость сборки до ~30%.
Если в проекте используется много модулей, то стоит также включить режим конфигурации при необходимости:
Чем больше модулей в вашем проекте, тем большее вы заметите ускорение, на малом количестве модулей его может и не быть.
Как известно, файл конфигурации сборки (build.gradle) предоставляет возможность определить Product Flavors и Build Types, что даёт нам массу вариантов для разделения сборок по назначению. Например, “Сборка с тестовым сервером”, “Сборка с боевым сервером”, ”Сборка с логированием” и другие. Использование их для расширения BuildConfig (который генерируется каждый раз при сборке) даёт нам потрясающую гибкость. Например, удобное переключение между back-end-сервером, с которым работает наше приложение; включение/выключение определённого функционала – например, логи.
В build.gradle:
В java коде:
Время не стоит на месте, а значит инструменты, библиотеки и Android имеют свойство обновляться. И если приложение развивается, то приходится открывать build.gradle и менять как минимум compileSdkVersion, buildToolsVersion, версии Android Support Library и Google Play Services. А если у нас в проекте используется много модулей или различные части библиотеки Google Play Services, это ведет к большому количеству мест изменений, и можно легко потерять время из-за опечатки в каком-то из файлов. Кроме того, возможно использование различных библиотек и инструментов в разных проектах, что плохо и может стать причиной проблем. Избежать подобной ситуации помогут gradle-переменные.
В самый верхний build.gradle добавляем
В остальных ./%module%/build.gradle их можно будет использовать, выглядеть это будет примерно так:
В большинстве случаев собирать аварийные завершения необходимо только в Release-сборках, которые мы выпускаем для пользователей/тестирования. Debug сборки разработчик использует для себя, и аварийные завершения будут видны ему в лог-файле, значит, дабы не засорять список реальных аварийных завершений у пользователей, необходимо выключить Crashlytics для Debug-сборок.
Задачу можно выполнить банальной проверкой типа сборки:
Но это не самое лучшее решение, т.к. плагин Fabric Gradle всё равно будет тратить время на генерацию и встраивание в ресурсы приложения уникального id сборки, чтобы Crashlytics back-end затем понял, какая сборка прислала данные. Поэтому применим более удобное решение, которое позволит ускорить время сборки debug-версии приложения.
В build.gradle:
После этого debug-сборки не будут получать id, и процесс сборки ускорится, но следует учитывать, что если разработчик попытается инициализировать в такой сборке Crashlytics, то приложение упадёт с выводом:
Т.е. обязательно оставьте проверку на тип сборки и используйте Crashlytics только для Release сборок или воспользуйтесь решением, приведённым в документации к Crashlytics на сайте Fabric:
В разрабатываемых нами приложениях мы часто используем сторонние библиотеки, например, Android Support Library, Google Play Services и другие. Многие из библиотек поставляются с различными внутренними ресурсами, которые в наших приложениях абсолютно не нужны. Например, Google Play Services поставляется с переводом на языки, которые ваше приложение не поддерживает. Вероятно, вы также не захотите поддерживать mdpi или tvdpi-разрешение в своём приложении.
Благодаря Android Gradle Plugin мы можем установить языки и разрешения, которые используются в приложении, остальные будут исключены, что позволит уменьшить вес приложения.
При необходимости можно подойти более радикально и начать использовать multi-APK, тем более когда появился новый удобный механизм Splits.
Этим рубрику полезных советов по Gradle закончим, их ещё много, но, на мой взгляд, вышеперечисленные являются наиболее интересными. Наверняка у вас есть и свои, интересно будет увидеть их в комментариях :) На этом всё, спасибо за внимание!
Речь пойдет о:
- Увеличении быстродействия
- Расширении BuildConfig
- Использовании переменных
- Выключении Crashlytics
- Уменьшении количества конфигураций ресурсов
1. Увеличиваем быстродействие
Время сборки напрямую влияет на скорость разработки. Тесты показывают, что каждая из версий, начиная с Gradle 2.0, становилась медленнее предыдущей. Однако затем разработчики исправились и хорошенько поработали над быстродействием в Gradle 2.4.
1. Поэтому первым делом следует убедиться, что вы используете актуальную версию Gradle 2.4+
sm:~ sm$ gradle -v
Gradle 2.4
2. Затем, удостоверившись, что вы пытаетесь ускорить свою рабочую машину, а не сервер CI, включить Gradle демон — это даст значительный прирост в скорости сборки.
Строки конфигурации стоит добавлять в файл ./%project%/gradle.properties, если вы хотите распространить конфигурацию на все проекты, то необходимо конфигурировать файл, лежащий в домашней папке вашего пользователя
~/.gradle/gradle.properties
org.gradle.daemon=true # включаем демон
Почему на CI-сервере не стоит включать Gradle Daemon
Gradle демон позволяет делать сборки более быстро, но при Gradle переиспользует runtime предыдущей сборки, по этой причине крайне важные требования для CI не выполняются. А именно стабильность и предсказуемость, чистота runtime и полная изолируемость от предыдущих сборок.
3. После чего, проверив что модули вашего проекта не используют друг-друга как зависимости, тем самым создавая перекрёстные ссылки, можно смело включать режим параллельного выполнения, что также ускорит скорость сборки до ~30%.
org.gradle.parallel=true # включаем режим параллельного выполнения
Если в проекте используется много модулей, то стоит также включить режим конфигурации при необходимости:
org.gradle.configureondemand=true
Чем больше модулей в вашем проекте, тем большее вы заметите ускорение, на малом количестве модулей его может и не быть.
2. Расширяем BuildConfig
Как известно, файл конфигурации сборки (build.gradle) предоставляет возможность определить Product Flavors и Build Types, что даёт нам массу вариантов для разделения сборок по назначению. Например, “Сборка с тестовым сервером”, “Сборка с боевым сервером”, ”Сборка с логированием” и другие. Использование их для расширения BuildConfig (который генерируется каждый раз при сборке) даёт нам потрясающую гибкость. Например, удобное переключение между back-end-сервером, с которым работает наше приложение; включение/выключение определённого функционала – например, логи.
В build.gradle:
android {
...
buildTypes {
debug {
buildConfigField "String", "SERVER_PREFIX", "\"test.\""
}
release {
buildConfigField "String", "SERVER_PREFIX", "\"\""
}
}
}
В java коде:
// …
public final class NetworkConstants {
// …
public static final String SERVER_ADDRESS = "http://" + BuildConfig.SERVER_PREFIX + "server.com/";
// …
}
Разница между Product Flavors и Build Types
Product Flavor — это механизм, который позволяет нам определять различные варианты сборки приложения. У одного проекта могут быть различные варианты сборки(flavors), при выборе варианта(flavor) будет изменяться генерируемое приложение.
Build Type — конфигурация того, как приложение будет упаковано. У каждого приложения по умолчанию есть два Build Type – debug и release. Можно сделать и другие. Идеологически Build Type не предназначен для изменения приложения, только упаковки. Собственно это и является основным различием, которое выливается в различные наборы параметров, которые предоставляются для настройки Product Flavors и Build Types.
Build Type — конфигурация того, как приложение будет упаковано. У каждого приложения по умолчанию есть два Build Type – debug и release. Можно сделать и другие. Идеологически Build Type не предназначен для изменения приложения, только упаковки. Собственно это и является основным различием, которое выливается в различные наборы параметров, которые предоставляются для настройки Product Flavors и Build Types.
3. Используем переменные
Время не стоит на месте, а значит инструменты, библиотеки и Android имеют свойство обновляться. И если приложение развивается, то приходится открывать build.gradle и менять как минимум compileSdkVersion, buildToolsVersion, версии Android Support Library и Google Play Services. А если у нас в проекте используется много модулей или различные части библиотеки Google Play Services, это ведет к большому количеству мест изменений, и можно легко потерять время из-за опечатки в каком-то из файлов. Кроме того, возможно использование различных библиотек и инструментов в разных проектах, что плохо и может стать причиной проблем. Избежать подобной ситуации помогут gradle-переменные.
В самый верхний build.gradle добавляем
// …
ext.compileSdkProjectVersion= 23
ext.buildToolsProjectVersion= '23.0.1'
ext.supportLibraryVersion = '23.1.0'
ext.googlePlayVersion = '8.3.01’
В остальных ./%module%/build.gradle их можно будет использовать, выглядеть это будет примерно так:
android {
compileSdkVersion compileSdkProjectVersion
buildToolsVersion buildToolsProjectVersion
//…
}
dependencies {
compile "com.android.support:appcompat-v7:$supportLibraryVersion"
compile "com.google.android.gms:play-services-base:$googlePlayVersion"
compile "com.google.android.gms:play-services-maps:$googlePlayVersion"
compile "com.google.android.gms:play-services-location:$googlePlayVersion"
}
4. Выключаем Crashlytics
В большинстве случаев собирать аварийные завершения необходимо только в Release-сборках, которые мы выпускаем для пользователей/тестирования. Debug сборки разработчик использует для себя, и аварийные завершения будут видны ему в лог-файле, значит, дабы не засорять список реальных аварийных завершений у пользователей, необходимо выключить Crashlytics для Debug-сборок.
Задачу можно выполнить банальной проверкой типа сборки:
// App.java
// …
public final class App extends Application {
// ...
@Override
public void onCreate() {
// …
if ( !BuildConfig.DEBUG ) {
Fabric.with(this, new Crashlytics());
}
// …
}
// …
}
Но это не самое лучшее решение, т.к. плагин Fabric Gradle всё равно будет тратить время на генерацию и встраивание в ресурсы приложения уникального id сборки, чтобы Crashlytics back-end затем понял, какая сборка прислала данные. Поэтому применим более удобное решение, которое позволит ускорить время сборки debug-версии приложения.
В build.gradle:
android {
//…
buildTypes {
debug {
ext.enableCrashlytics = false
// …
}
}
// …
}
После этого debug-сборки не будут получать id, и процесс сборки ускорится, но следует учитывать, что если разработчик попытается инициализировать в такой сборке Crashlytics, то приложение упадёт с выводом:
com.crashlytics.android.core.CrashlyticsMissingDependencyException:
This app relies on Crashlytics. Please sign up for access at https://fabric.io/sign_up`
Т.е. обязательно оставьте проверку на тип сборки и используйте Crashlytics только для Release сборок или воспользуйтесь решением, приведённым в документации к Crashlytics на сайте Fabric:
// App.java
// …
public final class App extends Application {
// ...
@Override
public void onCreate() {
// …
//Создаём Crashlytics,выключенный для debug сборок
Crashlytics crashlyticsKit = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
.build()
// Инициализируем Fabric с выключенным crashlytics.
Fabric.with(this, crashlyticsKit);
// …
}
// …
}
5. Уменьшаем количество конфигураций ресурсов
В разрабатываемых нами приложениях мы часто используем сторонние библиотеки, например, Android Support Library, Google Play Services и другие. Многие из библиотек поставляются с различными внутренними ресурсами, которые в наших приложениях абсолютно не нужны. Например, Google Play Services поставляется с переводом на языки, которые ваше приложение не поддерживает. Вероятно, вы также не захотите поддерживать mdpi или tvdpi-разрешение в своём приложении.
Благодаря Android Gradle Plugin мы можем установить языки и разрешения, которые используются в приложении, остальные будут исключены, что позволит уменьшить вес приложения.
// build.gradle
android {
defaultConfig {
resConfigs "en", "ru"
resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
}
При необходимости можно подойти более радикально и начать использовать multi-APK, тем более когда появился новый удобный механизм Splits.
Вместо заключения
Этим рубрику полезных советов по Gradle закончим, их ещё много, но, на мой взгляд, вышеперечисленные являются наиболее интересными. Наверняка у вас есть и свои, интересно будет увидеть их в комментариях :) На этом всё, спасибо за внимание!
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой вы хотели бы видеть следующую статью о Gradle?
45.79% Область видимости переменных в build-скриптах (одна из ключевых потенциальных ловушек)125
77.66% Управление зависимостями (детально рассмотрим возможности Gradle, будет круто)212
59.71% Фазы выполнения Gradle Build скриптов (вторая ключевая потенциальная ловушка)163
3.3% Мне это неинтересно, спасибо9
Проголосовали 273 пользователя. Воздержались 58 пользователей.