Большинство программистов, разрабатывающих для Android, хотя бы слышали о системе автоматической сборки Gradle. При этом, по моим наблюдениям, лишь немногие из использующих эту систему кодеров уделяют достаточно времени, чтобы как следует изучить ее возможности :). Самая частая причина звучит так: «Да ладно, это ж просто скрипт сборки, у меня есть задачи поважнее».
А ведь на самом деле Gradle может быть очень полезен как для простой настройки сборки, так и для решения весьма нестандартных задач! Об этом и пойдет речь сегодня.

 

Android Gradle plugin

Gradle сам по себе ничего не знает о том, как билдить Android-проект, в этом ему помогает плагин, который разрабатывается вместе с Android SDK. Если ты только недавно начал осваивать программирование под Android, то мог и не заметить, что в главном сборочном скрипте build.gradle студия самостоятельно добавляет зависимость от этого плагина.

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        // Android Gradle plugin добавляется здесь
        classpath 'com.android.tools.build:gradle:2.1.3'
    }
}

А в скрипте твоего основного модуля этот плагин автоматически подключается строчкой apply plugin: 'com.android.application'. Именно поэтому у тебя в скрипте есть секция android { ... }, в которой ты указываешь версию Build Tools, версии SDK для сборки и прочее.

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

 

Добавляем свои поля в BuildConfig

BuildConfig — это автоматически генерируемый при сборке класс, который содержит только константы. Этот класс генерируется отдельно для каждого модуля в твоем проекте и по умолчанию включает в себя информацию об ID приложения, версии, типе сборки.

// Типичный BuildConfig
public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "ru.ingos.ingosview";
  public static final int VERSION_CODE = 37;
  public static final String VERSION_NAME = "2.9-offline";
}

Редактирование вручную этого файла бесполезно, так как он все равно перезатрется новыми данными при сборке. Зато Android-плагин может добавлять в него те поля, которые ты скажешь.

android {

    defaultConfig {
        applicationId "example.myawesomeapp"
        minSdkVersion 16
        targetSdkVersion 24
        versionCode 1
        versionName "MyApp-v1.0"
        buildConfigField "String", "SERVER", '"https://my-server.example"'
        buildConfigField "long", "TIMEOUT ", "${1000 * 60 * 5}" // 5 минут
    }
    // Прочее
}

Первый параметр — тип константы, второй — имя, третий — значение, все просто. Заметь, что значение поля TIMEOUT вычисляется на этапе сборки и в BuildConfig попадет уже как число 300 000. Теперь ты можешь конфигурировать свой любимый HTTP-клиент, просто ссылаясь на константы в BuildConfig.

// Пример использования BuildConfig
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(BuildConfig.TIMEOUT, TimeUnit.MILLISECONDS);
okHttpClient.newCall(new Request.Builder().url(BuildConfig.SERVER).build());
 

Добавляем свои данные в ресурсы

Принцип точно такой же, что и с BuildConfig, но позволяет добавлять значения в файл ресурсов. Но зачем добавлять ресурс из конфига, если проще это сделать, как обычно, в XML-файле? Просто потому, что в скрипте, так же как и в случае с BuildConfig.TIMEOUT, значение ресурса можно вычислить. Например, сохранить дату сборки:

resValue "string", "BUILD_TIME", "${System.currentTimeSeconds()}"

Gradle создаст специальный файл generated.xml примерно такого содержания (только, разумеется, с правильными угловыми скобочками):

[?xml version="1.0" encoding="utf-8"?]
[resources]
    [!-- Automatically generated file. DO NOT MODIFY --]
    [!-- Values from default config. --]
    [string name="BUILD_TIME" translatable="false"]1471574224[/string]
[/resources]

И пусть тебя не смущает, что мы храним время в формате String. К сожалению, Android SDK не умеет хранить в ресурсах long, а в 32-битный integer время не влезет.

 

Создаем разные варианты сборки

Пожалуй, уже все Android-программисты знают о существовании встроенных типов сборок debug и release. Чуть меньше — о том, что можно создавать свои типы сборок. Еще меньше тех, кто дополнительно применяет productFlavors. Но давай по порядку.


…Все Android-программисты знают о существовании встроенных типов сборок debug и release. Чуть меньше — о том, что можно создавать свои типы сборок. Еще меньше тех, кто дополнительно применяет productFlavors

Мы используем build types, чтобы иметь возможность собирать приложение с существенными отличиями. Эти отличия обычно связаны с тем, как мы собираем приложение: для отладки или для релиза, с обфускацией кода или без, каким сертификатом оно будет подписано.

buildTypes {

    release {
        minifyEnabled true // Включаем обфускацию
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-all.txt'
        signingConfig signingConfigs.release // Указываем релизный конфиг для подписывания
    }

    debug {
        minifyEnabled false // Отключаем обфускацию
        signingConfig signingConfigs.debug // Указываем отладочный конфиг для подписывания
    }

    qa {
        minifyEnabled false // Отключаем обфускацию
        signingConfig signingConfigs.debug // Указываем отладочный конфиг для подписывания
        testCoverageEnabled true // Включаем анализ покрытия тестами
    }

}

Чтобы собрать нужный тип, выполняем команду gradle assemble<ИмяТипаСборки>, например gradle assembleDebug или gradle assembleQa.

INFO


Есть два пути настройки Gradle. Ты можешь установить его на машину самостоятельно или использовать Gradle Wrapper внутри проекта. В первом случае Gradle будет доступен тебе глобально через команду gradle из консоли. Во втором случае сборку можно запускать через специальную программу-обертку — gradlew. Второй способ предпочтительнее, так как может работать с любой версией Gradle без переустановки. Тем более что при создании проекта в Android Studio этот способ работает по умолчанию. Подробнее о Gradle Wrapper ты можешь почитать по ссылке.

Product flavors дополняют build types и вносят еще один уровень гибкости в настройку сборки. Используй их, когда нужно, скажем так, не глобально изменить приложение, — это могут быть брендинг (иконки, цвета, тексты), окружение (адрес сервера, платформа, trial- или pro-версии).

productFlavors {

    trial {
        versionName "MyAwesomeApp-trial"
        buildConfigField "String", "SERVER", '"https://trial.my-server.example"'
    }

    pro {
        versionName "MyAwesomeApp-pro"
        buildConfigField "String", "SERVER", '"https://pro.my-server.example"'
    }
}

Build type и product flavor в сумме дают так называемый итоговый Build Variant, собрать который можно по схеме gradle assemble<ИмяПродукта><ИмяТипаСборки>. Если ты хочешь запустить эти сборки не из консоли, а из студии, открой вкладку Build Variants и выбери то, что тебе нужно, из списка, как на рис. 1.

Продолжение доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все материалы на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи один материал

Заинтересовала информация, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для материалов, опубликованных более двух месяцев назад.


1 комментарий

  1. clicker314

    04.10.2016 at 14:07

    Уважаемая редакция, верните голосование за посты. Я поставлю этому посту +

Оставить мнение

Check Also

Android: инструменты пентестера, уязвимости экрана блокировки iOS и множество советов по Kotlin

Сегодня в выпуске: десять инструментов пентестера, уязвимости экрана блокировки iOS, взлом…