03.03.2017 Views

№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 />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!