Объектно-ориентированный 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()
}
  • переименовать все файлы формата .gradle в .gradle.kts, согласно [инструкции](https://developer.android.com/studio/build/migrate-to-kts#:~:text=In the future%2C KTS will,time checking and IDE support.)

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

Для разработчиков, использующих 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/


Интересные статьи

Интересные статьи

Вторая статья из цикла о функциональном программировании на Kotlin с разбором принципа работы, концепции и способов применения каррирования на практике.
Недавно на проекте интегрировал модуль CRM Битрикса c виртуальной АТС Ростелеком. Делал по стандартной инструкции, где пошагово показано, какие поля заполнять. Оказалось, следование ей не гаран...
Как широко известно, с 1 января 2017 года наступает три важных события в жизни интернет-магазинов.
Бизнес-смыслы появились в Битриксе в начале 2016 года, но мало кто понимает, как их правильно использовать для удобной настройки интернет-магазинов.
Друзья, в преддверии выходных хотим поделиться с вами еще одной интересной публикацией, которую хотим приурочить к запуску новой группы по курсу «Разработчик JavaScript». Потратив последни...