Обзор сборки Gradle

Приложения Android обычно собираются с помощью системы сборки Gradle . Прежде чем углубляться в детали настройки сборки, мы рассмотрим основные принципы, лежащие в её основе, чтобы вы могли увидеть систему в целом.

Что такое сборка?

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

Задачи инкапсулируют команды, которые преобразуют свои входные данные в выходные. Плагины определяют задачи и их конфигурацию. Применение плагина к вашей сборке регистрирует его задачи и связывает их между собой, используя их входные и выходные данные. Например, применение плагина Android Gradle (AGP) к вашему файлу сборки зарегистрирует все задачи, необходимые для сборки APK или библиотеки Android. Плагин java-library позволяет собрать jar-файл из исходного кода Java. Аналогичные плагины существуют для Kotlin и других языков, но другие плагины предназначены для расширения возможностей плагинов. Например, плагин protobuf предназначен для добавления поддержки protobuf к существующим плагинам, таким как AGP или java-library .

Gradle предпочитает соглашения конфигурации, поэтому плагины поставляются с удобными значениями по умолчанию из коробки, но вы можете дополнительно настроить сборку с помощью декларативного предметно-ориентированного языка (DSL). DSL разработан таким образом, чтобы вы могли указать, что именно собирать, а не как . Логика плагинов управляет «как». Эта конфигурация задаётся в нескольких файлах сборки вашего проекта (и подпроектов).

Входными данными задачи могут быть файлы и каталоги, а также другая информация, закодированная в типах Java (целые числа, строки или пользовательские классы). Выходными данными могут быть только каталоги или файлы, поскольку они должны быть записаны на диск. Подключение выходных данных задачи к входным данным другой задачи связывает задачи таким образом, что одна из них должна быть запущена раньше другой.

Хотя Gradle поддерживает запись произвольного кода и объявлений задач в файлах сборки, это может затруднить понимание сборки инструментами и её сопровождение вами. Например, вы можете писать тесты для кода внутри плагинов, но не для самих файлов сборки. Вместо этого следует ограничить логику сборки и объявления задач плагинами (которые вы или кто-то другой определил) и указать, как вы хотите использовать эту логику, в файлах сборки.

Что происходит при запуске сборки Gradle?

Сборка Gradle выполняется в три фазы. На каждой из этих фаз выполняются различные части кода, которые вы определяете в файлах сборки.

  • Инициализация определяет, какие проекты и подпроекты будут включены в сборку, и настраивает пути к классам, содержащие файлы сборки и применённые плагины. Этот этап фокусируется на файле настроек, в котором объявляются проекты для сборки, а также на местах, откуда будут загружаться плагины и библиотеки.
  • Конфигурация регистрирует задачи для каждого проекта и выполняет файл сборки, чтобы применить пользовательскую спецификацию сборки. Важно понимать, что код конфигурации не будет иметь доступа к данным или файлам, созданным во время выполнения.
  • Выполнение осуществляет фактическую «сборку» вашего приложения. Результатом конфигурации является направленный ациклический граф (DAG) задач, представляющий все необходимые этапы сборки, запрошенные пользователем (задачи, указанные в командной строке или заданные по умолчанию в файлах сборки). Этот граф отображает взаимосвязь между задачами, либо явно заданную в объявлении задачи, либо основанную на её входных и выходных данных. Если входные данные задачи являются выходными данными другой задачи, то она должна выполняться после этой задачи. На этом этапе устаревшие задачи запускаются в порядке, указанном в графе; если входные данные задачи не изменились с момента её последнего выполнения, Gradle пропустит её.

Более подробную информацию см. в разделе Жизненный цикл Gradle Build .

Конфигурация DSL

Gradle использует предметно-ориентированный язык (DSL) для настройки сборок. Этот декларативный подход фокусируется на указании данных, а не на пошаговых (императивных) инструкциях. Вы можете писать файлы сборки на Kotlin или Groovy, но мы настоятельно рекомендуем использовать Kotlin.

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

Например, настройка Android-части вашей сборки может выглядеть так:

Котлин

android {
    namespace = "com.example.app"
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

Круто

android {
    namespace = 'com.example.app'
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = 'com.example.app'
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

На самом деле код DSL выглядит примерно так:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var namespace: String?

    fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
        ...
    }

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

Каждый блок в DSL представлен функцией, которая принимает лямбда-выражение для настройки и свойство с тем же именем для доступа к нему. Благодаря этому код в файлах сборки больше похож на спецификацию данных.

Внешние зависимости

Система сборки Maven представила спецификацию зависимостей , систему хранения и управления ими. Библиотеки хранятся в репозиториях (серверах или каталогах) с метаданными, включающими их версии и зависимости от других библиотек. Вы указываете, в каких репозиториях выполнять поиск, какие версии зависимостей использовать, а система сборки загружает их во время сборки.

Артефакты Maven идентифицируются по имени группы (компания, разработчик и т. д.), имени артефакта (имя библиотеки) и версии этого артефакта. Обычно это представлено в виде group:artifact:version .

Такой подход значительно улучшает управление сборкой. Такие репозитории часто называют «репозиториями Maven», но на самом деле всё дело в способе упаковки и публикации артефактов. Эти репозитории и метаданные повторно используются в нескольких системах сборки, включая Gradle (и Gradle может публиковать данные в этих репозиториях). Публичные репозитории позволяют предоставлять общий доступ, а корпоративные репозитории позволяют хранить внутренние зависимости внутри компании.

Вы также можете разбить свой проект на модули, состоящие из подпроектов (также известных как «модули» в Android Studio), которые также можно использовать в качестве зависимостей. Каждый подпроект создаёт выходные данные (например, jar-файлы), которые могут использоваться подпроектами или вашим проектом верхнего уровня. Это может сократить время сборки, позволяя изолировать части, требующие пересборки, а также лучше распределить обязанности в приложении.

Более подробно о том, как указать зависимости, мы поговорим в разделе Добавление зависимостей сборки .

Варианты сборки

При создании приложения для Android обычно требуется создать несколько вариантов . Варианты содержат разный код или создаются с разными опциями, а также различаются по типам сборки и вариантам продукта.

Типы сборки различаются заявленными параметрами. По умолчанию AGP устанавливает типы сборки «релиз» и «отладка», но вы можете изменить их и добавить дополнительные (например, для подготовки к запуску или внутреннего тестирования).

Отладочная сборка не минифицирует и не обфусцирует ваше приложение, ускоряя его сборку и сохраняя все символы в исходном виде. Она также помечает приложение как «отлаживаемое», подписывая его универсальным ключом отладки и предоставляя доступ к установленным файлам приложения на устройстве. Это позволяет просматривать сохранённые данные в файлах и базах данных во время работы приложения.

Сборка релиза оптимизирует приложение, подписывает его вашим ключом релиза и защищает установленные файлы приложения.

Используя варианты продукта , вы можете изменить включённые варианты исходного кода и зависимостей для приложения. Например, вы можете создать версии «демо» и «полная» или, возможно, «бесплатная» и «платная». Вы записываете свой общий исходный код в каталог «основного» набора исходных кодов и переопределяете или добавляете исходный код в набор исходных кодов с именем, соответствующим выбранному варианту.

AGP создаёт варианты для каждой комбинации типа сборки и варианта продукта. Если варианты не определены, варианты именуются по типам сборки. Если определены оба варианта, вариант будет назван <flavor><Buildtype> . Например, для типов сборки release и debug , а также вариантов demo и full , AGP создаст варианты:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

Следующие шаги

Теперь, когда вы познакомились с концепциями сборки, взгляните на структуру сборки Android в вашем проекте.