Большинство программистов, разрабатывающих для 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 комментарий

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Windows 10 против шифровальщиков. Как устроена защита в обновленной Windows 10

Этой осенью Windows 10 обновилась до версии 1709 с кодовым названием Fall Creators Update …