Объектно-ориентированный Gradle. Настраиваем Build types в Android, используя Kotlin DSL

В этой статье мы поговорим о том, как наша команда перешла на Kotlin DSL для описания Gradle файлов, и как в итоге мы получили типы сборок, описанные классами и имеющие общий интерфейс.

Меня зовут Давид, и я с 2018 года разрабатываю в Константе приложения под платформу Android, как большие и нацеленные на аудиторию в несколько сотен тысяч уникальных пользователей, так и рассчитанные на внутреннее использование. Вообще, в Константе много проектов, каждый из которых по-своему интересен и уникален. Например, есть приложения, ориентированные на несколько разных рынков, а есть мессенджер, заточенный на конфиденциальность передаваемых данных, который я сейчас делаю с нуля, и он пока используется внутри компании.

У нас большое сообщество Android разработчиков, и мы часто делимся опытом не только внутри команды, но и с коллегами в сети. В рамках одного из наших проектов мы решили попробовать кое-что новое, а именно — отказаться от Groovy в пользу Kotlin DSL для Gradle файлов. Об этом я вам и расскажу.

Решение использовать Kotlin DSL было принято по нескольким причинам:

  • удобство. Код на Kotlin DSL более читабелен, компактен и дает больше возможностей в рамках традиционного IDE

  • любовь к Kotlin. Этот язык перспективен и прекрасен, и мы стараемся пользоваться его прелестями, где только можно

  • Рекомендация от Google

Итак, мы приступили к написанию скриптов. Для начала определили, какие типы сборок будут в проекте. В итоге остановились на таком варианте:

  • debug — тип по-умолчанию. Используется для отладки во время разработки

  • qa — сборка, используемая QA инженерами внутри команды для тестирования функционала в рамках конкретной задачи

  • preProd — сборка, используемая QA инженерами внутри команды для проведения регрессионного тестирования (a.k.a release-candidate)

  • release — сборка для конечных пользователей

Этот список может отличаться от выбранного вами. Наш подход позволяет безболезненно добавлять / убирать типы сборок.

После этого мы добавили поддержку Kotlin DSL в проект. Вот пошаговая инструкция:

  • добавить папку с названием buildSrc на уровне проекта

  • создать в ней файл с названием build.gradle.kts

  • добавить туда скрипт:

import org.gradle.kotlin.dsl.`kotlin-dsl` plugins { kotlin-dsl } repositories { jcenter() } 

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

Для разработчиков, использующих Groovy, привычно, когда каждый тип должен быть указан в Gradle с его настройками. Обычно это выглядит так:

buildTypes{ getByName("debug"){ applicationIdSuffix = ".debug" } create("qa"){ applicationIdSuffix = ".qa" initWith(getByName("debug")) isMinifyEnabled = false } create("preProd"){ applicationIdSuffix = ".preprod" isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } create("release"){ applicationIdSuffix = ".release" isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } 

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

В первую очередь, мы создали интерфейс AppBuild в папке buildSrc, чтобы иметь к нему доступ из Gradle. Получилось так:

interface AppBuild { val name: String  val suffix: String  val isDebuggable: Boolean  val signingParams: SigningParams?  } 

Затем мы создали Build классы, реализующие этот интерфейс. Ниже показан класс для QA:

object QaBuild : AppBuild { override val name: String     get() = "qa"  override val suffix: String     get() = ".$name"  override val isDebuggable: Boolean     get() = true  override val signingParams: SigningParams?     get() = null  } 

Затем в AppBuild.companionObject добавили метод, возвращающий список всех Build классов:

interface AppBuild {  companion object {     fun getAll(): List<AppBuild> =listOf(         QaBuild,         PreProdBuild,         ReleaseBuild     ) }  val name: String  val suffix: String  val isDebuggable: Boolean  val signingParams: SigningParams?  } 

После того, как мы получили объектно-ориентированные Build настройки, осталось добавить их в Gradle:

buildTypes{ AppBuild         .getAll()         .forEach { build-> create(build.name){ applicationIdSuffix = build.suffix                 isMinifyEnabled = build.isMinifyEnabled                 if (isDebuggable) {                    initWith(getByName("debug"))                 }                 signingParams                    ?.let { params ->                       signingConfig = signingConfigs                                          .getByName(build.name)                       proguardFiles(                           getDefaultProguardFile(params.proguard),                           params.proguardRules                       )                    } }         } } 

И SigningConfigs:

signingConfigs{ AppBuild         .getAll()         .forEach { build-> create(build.name){  signingParams                    ?.let { params ->                        storeFile = file(params.keystoreLocation)                        storePassword = params.keystorePassword                        keyAlias = params.aliasName                        keyPassword = params.aliasPassword                   } }         } } 

Это все… В последствии мы получили BuildVariants с типами debugqapreProd и release. При этом мы не создавали отдельный тип debug, так как он уже был настроен изначально.

Мы выделил для себя такие плюсы этого подхода:

  • читабельность: все типы находятся в одном месте, а их настройки указаны в виде свойств;

  • расширяемость: в любой момент мы можем добавить новый build с его настройками, и все, что от нас потребуется — это Sync project;

  • гибкость: если нам понадобится сменить путь keystoresuffix или что-то еще, мы сделаем это всего один раз;

  • удобство при многомодульности: мы не пишем про все build типы во всех модулях отдельно, а всего лишь добавляем небольшой кусок кода;

Если говорить о минусах использования Kotlin DSL, обратили внимание на следующее:

  • мало документации в сети. Наша команда потратила немало времени на переход из Groovy на Kotlin DSL.

  • время сборки увеличивается. Об этом написано в официальной документации. Но стоит отметить, что при грамотном подходе к проекту (разбиение на модули и правильная настройка зависимостей) разницу не будете ощущать.

Вот так наша команда перешла на Kotlin DSL, надеемся, что наша статья будет полезна тем, кто только планирует этот переход.

Спасибо за внимание. До новых интересных задач!


ссылка на оригинал статьи https://habr.com/ru/company/constanta/blog/669878/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *