Взаимозависимости инструментов и библиотек

Зависимости сборки — это внешние компоненты, необходимые для успешной сборки проекта. Сборка может зависеть от библиотек, плагинов, подпроектов , Android SDK, таких инструментов, как компиляторы Kotlin и Java , сред разработки, таких как Android Studio , и самого Gradle .

Каждая зависимость сама по себе может требовать других зависимостей. Мы называем эти транзитивные зависимости и можем быстро увеличить общее количество зависимостей, используемых вашим приложением. Если вы хотите обновить зависимость, будь то библиотека, инструмент или Android SDK, это обновление может быть каскадным, обновляя многие другие зависимости.

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

Семантическое управление версиями соответствует формату major.minor.patch . Например, в номере версии 4.8.3 4 — major версия, 8 — minor версия и 3 — номер patch . При изменении major части библиотеки могут произойти критические изменения в API или поведении. Это может повлиять на поведение вашей сборки или приложения.

Когда изменяются minor (новые функции) или patch (исправления ошибок) части, разработчики библиотеки сообщают вам, что библиотека по-прежнему совместима и не должна влиять на ваше приложение.

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

Отношения в вашей сборке

Сборки Android содержат отношения между:

  • Исходный код — код и ресурсы, которыми вы управляете.
  • Зависимости библиотеки — внешние библиотеки или модули, которые ваш проект и подпроекты включают при сборке.
  • Инструменты — компиляторы, плагины и SDK, которые преобразуют ваш исходный код в приложение или библиотеку.
Построение зависимостей и их отношений
Рисунок 1. Построение отношений

Исходный код

Ваш исходный код — это код Kotlin или Java, который вы пишете в своем приложении или библиотеке. (Подробнее об использовании C++ см. в Android NDK .)

Исходный код зависит от библиотек (включая библиотеки времени выполнения Kotlin и Java) и Android SDK и требует соответствующего компилятора Kotlin или Java.

Некоторый исходный код содержит аннотации, требующие дополнительной обработки. Например, если вы пишете код Jetpack Compose , вы добавляете аннотации, такие как @Composable , которые необходимо обработать плагином компилятора Compose Kotlin . Другие аннотации могут обрабатываться процессором символов Kotlin (KSP) или отдельными инструментами обработки аннотаций .

Зависимости библиотеки

Библиотеки содержат байт-код, полученный как часть вашего приложения. Это может быть JAR-файл Java, библиотека Android (AAR) или подпроект вашей сборки. Многие библиотеки используют семантическое управление версиями , что может помочь вам понять, остаются ли они совместимыми (или нет) при обновлении.

Библиотеки могут зависеть от других библиотек при повторном использовании, что называется транзитивной зависимостью . Это уменьшает количество зависимостей, которыми необходимо явно управлять; вы указываете зависимости, которые используете напрямую, и Gradle подтягивает их вместе с этими транзитивными зависимостями. Имейте в виду, что при обновлении прямых зависимостей они могут обновить и транзитивные зависимости.

Иногда библиотеке могут потребоваться минимальные версии Android SDK во время выполнения ( minSdk ) или во время компиляции ( compileSdk ). Это необходимо, когда библиотека использует функции, включенные в Android SDK или предоставляемые API JDK. Эффективный minSdk вашего приложения — это самый высокий minSdk запрошенный вашим приложением и всеми его прямыми и транзитивными зависимостями библиотеки.

Для использования некоторых библиотек может потребоваться использование определенного плагина Gradle. Эти вспомогательные плагины часто устанавливают процессоры символов Kotlin или другие обработчики аннотаций, которые генерируют код или изменяют компиляцию исходного кода для поддержки использования функций библиотеки. Например, Jetpack Room включает аннотации и KSP, который преобразует их в сгенерированный код для извлечения и изменения данных в базе данных. Jetpack Compose требует, чтобы плагин компилятора Compose изменял аннотированные функции, чтобы управлять тем, как и когда эта функция перезапускается.

Инструменты

Градл

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

Плагины Gradle

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

Составители

Компилятор Kotlin или Java преобразует ваш исходный код в исполняемый байт-код. Компилятор Kotlin предоставляет API-интерфейс плагина, который позволяет запускать внешний анализ и генерацию кода непосредственно внутри компилятора, получая доступ к анализируемой структуре кода.

Плагины компилятора

Плагины компилятора выполняют анализ и генерацию кода внутри компилятора Kotlin, пока компилятор Kotlin анализирует ваш код, и устанавливаются, когда вы применяете их плагины Gradle к сборке.

Android SDK

Android SDK содержит платформу Android и API Java для конкретной версии Android, а также соответствующие инструменты. Эти инструменты помогут вам управлять SDK, создавать приложения, а также взаимодействовать с устройствами Android и эмулировать их.

Каждая версия Android SDK предоставляет определенные API Java, к которым может получить доступ ваш исходный код, и устраняет поддержку использования этих API в более ранних версиях Android.

ЯДК

Комплект разработки Java, содержащий библиотеки Java и исполняемые файлы для компиляции исходного кода Java и запуска приложений Java. В сборке Android задействовано несколько JDK. Дополнительные сведения см. в разделе «Версии Java в сборках Android» .

Области Gradle

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

Например, AGP определяет области implementation и api — ваш способ указать, должна ли зависимость быть доступна пользователям вашего подпроекта. См. раздел Настройка зависимостей для описания этих и других областей, используемых в сборке Android.

Добавьте зависимости библиотеки в блок dependencies ваших файлов сборки, либо в виде строк group:artifact:version :

Котлин

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation("com.example:library1:1.2.3")
    api("com.example:library2:1.1.1")
}

классный

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation 'com.example:library1:1.2.3'
    api 'com.example:library2:1.1.1'
}

или в Каталоге версий :

# Version catalog - gradle/libs.versions.toml
[versions]
exampleLib = "1.2.3"
examplePlugin = "2.3.4"

[libraries]
example-library = { group = "com.example", name = "library", version.ref = "exampleLib" }

[plugins]
example-plugin = { id = "com.example.plugin", version.ref = "examplePlugin" }

и укажите сгенерированные переменные в файлах сборки:

Котлин

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation(libs.example.library)
}

классный

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation libs.example.library
}