№9 (сентябрь 2016)
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
CODING<br />
ЗАВОДНОЙ<br />
СКРИПТИНГ<br />
ДЛЯ ANDROID<br />
ЗНАКОМИМСЯ<br />
С КРУТОЙ СИСТЕМОЙ<br />
АВТОМАТИЧЕСКОЙ<br />
СБОРКИ GRADLE<br />
Артур Глызин<br />
Большинство программистов, разрабатывающих<br />
для Android, хотя бы слышали о системе автоматической<br />
сборки Gradle. При этом, по моим наблюдениям, лишь немногие<br />
из использующих эту систему кодеров уделяют достаточно<br />
времени, чтобы как следует изучить ее возможности<br />
:). Самая частая причина звучит так: «Да ладно, это ж<br />
просто скрипт сборки, у меня есть задачи поважнее».<br />
А ведь на самом деле Gradle может быть очень полезен как для простой настройки<br />
сборки, так и для решения весьма нестандартных задач! Об этом<br />
и пойдет речь сегодня.<br />
ANDROID GRADLE PLUGIN<br />
Gradle сам по себе ничего не знает о том, как билдить Android-проект, в этом<br />
ему помогает плагин, который разрабатывается вместе с Android SDK. Если<br />
ты только недавно начал осваивать программирование под Android, то мог<br />
и не заметить, что в главном сборочном скрипте build.gradle студия самостоятельно<br />
добавляет зависимость от этого плагина.<br />
А в скрипте твоего основного модуля этот плагин автоматически подключается<br />
строчкой apply plugin: 'com.android.application'. Именно поэтому<br />
у тебя в скрипте есть секция android { ... }, в которой ты указываешь версию<br />
Build Tools, версии SDK для сборки и прочее.<br />
Перед тем как мы попытаемся глубже разобраться в работе самого Gradle,<br />
я покажу тебе несколько полезных вещей, которые умеет делать этот плагин<br />
и о которых ты мог не знать.<br />
Добавляем свои поля в BuildConfig<br />
BuildConfig — это автоматически генерируемый при сборке класс, который содержит<br />
только константы. Этот класс генерируется отдельно для каждого модуля<br />
в твоем проекте и по умолчанию включает в себя информацию об ID приложения,<br />
версии, типе сборки.<br />
Редактирование вручную этого файла бесполезно, так как он все равно перезатрется<br />
новыми данными при сборке. Зато Android-плагин может добавлять<br />
в него те поля, которые ты скажешь.<br />
Первый параметр — тип константы, второй — имя, третий — значение, все<br />
просто. Заметь, что значение поля TIMEOUT вычисляется на этапе сборки<br />
и в BuildConfig попадет уже как число 300 000. Теперь ты можешь конфигурировать<br />
свой любимый HTTP-клиент, просто ссылаясь на константы в BuildConfig.<br />
Добавляем свои данные в ресурсы<br />
Принцип точно такой же, что и с BuildConfig, но позволяет добавлять значения<br />
в файл ресурсов. Но зачем добавлять ресурс из конфига, если проще<br />
это сделать, как обычно, в XML-файле? Просто потому, что в скрипте, так же<br />
как и в случае с BuildConfig.TIMEOUT, значение ресурса можно вычислить. Например,<br />
сохранить дату сборки:<br />
Gradle создаст специальный файл generated.xml примерно такого содержания:<br />
И пусть тебя не смущает, что мы храним время в формате String. К сожалению,<br />
Android SDK не умеет хранить в ресурсах long, а в 32-битный integer время<br />
не влезет.<br />
Создаем разные варианты сборки<br />
Пожалуй, уже все Android-программисты знают о существовании встроенных<br />
типов сборок debug и release. Чуть меньше — о том, что можно создавать<br />
свои типы сборок. Еще меньше тех, кто дополнительно применяет<br />
productFlavors. Но давай по порядку.<br />
...Все Android-программисты знают о существовании встроенных типов<br />
сборок debug и release. Чуть меньше — о том, что можно создавать свои типы<br />
сборок. Еще меньше тех, кто дополнительно применяет productFlavors.<br />
Мы используем build types, чтобы иметь возможность собирать приложение<br />
с существенными отличиями. Эти отличия обычно связаны с тем, как мы собираем<br />
приложение: для отладки или для релиза, с обфускацией кода или без,<br />
каким сертификатом оно будет подписано.<br />
Чтобы собрать нужный тип, выполняем команду gradle assemble,<br />
например gradle assembleDebug или gradle assembleQa.<br />
INFO<br />
Есть два пути настройки Gradle. Ты можешь установить его на машину самостоятельно<br />
или использовать Gradle Wrapper внутри проекта. В первом случае<br />
Gradle будет доступен тебе глобально через команду gradle из консоли.<br />
Во втором случае сборку можно запускать через специальную программу-обертку<br />
— gradlew. Второй способ предпочтительнее, так как может работать<br />
с любой версией Gradle без переустановки. Тем более что при создании проекта<br />
в Android Studio этот способ работает по умолчанию. Подробнее о Gradle<br />
Wrapper ты можешь почитать по ссылке.<br />
Product flavors дополняют build types и вносят еще один уровень гибкости в настройку<br />
сборки. Используй их, когда нужно, скажем так, не глобально изменить<br />
приложение, — это могут быть брендинг (иконки, цвета, тексты), окружение<br />
(адрес сервера, платформа, trial- или pro-версии).<br />
Build type и product flavor в сумме дают так называемый итоговый Build Variant,<br />
собрать который можно по схеме gradle assemble.<br />
Если ты хочешь запустить эти сборки не из консоли, а из студии, открой<br />
вкладку Build Variants и выбери то, что тебе нужно, из списка, как на рис. 1.<br />
Рис. 1. Выбор Build Variant в Android Studio<br />
Каждая из секций buildTypes и productFlavors {...} может иметь свои<br />
buildConfigField {...}, resValue, versionName и другие параметры, которые<br />
будут приоритетнее, чем те, что объявлены в defaultConfig {...}.<br />
Настраиваем информацию о приложении<br />
Имея несколько вариантов сборок, ты точно захочешь их идентифицировать<br />
или различать после установки. Как раз для этого у Android-плагина есть парочка<br />
параметров — applicationIdSuffix и versionNameSuffix, которые добавляют<br />
к существующему ID приложения и к существующей версии то, что ты<br />
пожелаешь.<br />
С таким конфигом команда gradle assembleTrialRelease соберет тебе приложение<br />
с applicationId="example.myawesomeapp.release" и названием версии<br />
MyAwesomeApp-trial.<br />
Заканчивая тему с Android-плагином для Gradle, нужно сказать, что это<br />
только часть его возможностей. Плагин постоянно развивается и приобретает<br />
новые фичи. На сайте tools.android.com есть подробный гайд по его использованию.<br />
GRADLE DSL<br />
А теперь давай попробуем разобраться, почему конфигурация сборки<br />
в Gradle называется скриптом, из чего состоит этот скрипт и почему он выглядит<br />
так, как выглядит. Gradle часто называют объединением систем сборки Ant<br />
и Maven. С одной стороны, Gradle, как и Maven, обеспечивает декларативный<br />
подход к сборке, когда программист лишь объявляет нужные значения и параметры,<br />
а система сама знает, как сделать всю остальную работу самостоятельно.<br />
Именно этим мы занимались в предыдущей части.<br />
С другой стороны, Gradle, как и Ant, умеет выполнять команды, но пишутся<br />
они не в XML-файле, а уже с помощью Gradle DSL (domain-specific programming<br />
language), написанном на Groovy. В мире Gradle эти команды называются<br />
Tasks (задачи). Задачи можно делать зависимыми от других задач и таким образом<br />
строить граф их выполнения. По сути, цепочка задач и установленные<br />
параметры и есть скрипт сборки приложения.<br />
В прошлой части статьи, когда мы выполняли команды вроде gradle<br />
assembleRelease, на самом деле мы запускали уже готовую одноименную задачу.<br />
Она не взялась из ниоткуда, ее нам подготовил Android-плагин. Ты всегда<br />
можешь посмотреть список доступных команд, выполнив gradle tasks.<br />
Попробуй, и ты увидишь, как много задач тебе уже предоставлено.<br />
Рис. 2. Типичный набор задач в Android-проекте<br />
Стандартные команды ты можешь изучить, запуская их с помощью gradle<br />
help или gradle install. А как насчет собственных задач? Легко — давай же<br />
скорее напишем Hello Gradle!<br />
Добавь эту задачу в свой build-скрипт, и ты сможешь запустить ее gradle hello.<br />
Она появится также в списке задач (gradle tasks) в разделе Other tasks. Если<br />
ты знаком с Groovy, ты сразу заметишь, что тело задачи — это просто замыкание<br />
(closure) с кодом, печатающим слова. Вся мощь Gradle и заключается в том,<br />
что в теле задачи можно писать Groovy-код, а значит, можно создавать задачи,<br />
делающие что угодно, если это можно уложить в программный код.<br />
Прежде чем мы напишем что-то действительно полезное, давай я тебе покажу<br />
еще пару примеров манипулирования задачами.<br />
Пример 1: добавляем зависимости к задаче<br />
Мы написали две задачи, печатающие отдельно слова Hello и world. Операция<br />