На этой странице показано, как можно настроить варианты сборки для создания различных версий вашего приложения из одного проекта, а также как правильно управлять зависимостями и конфигурациями подписи.
Каждый вариант сборки представляет собой отдельную версию вашего приложения, которую вы можете собрать. Например, вы можете создать одну бесплатную версию приложения с ограниченным набором контента и другую платную версию с расширенным набором. Вы также можете создавать разные версии приложения для разных устройств, в зависимости от уровня API или других характеристик устройств.
Варианты сборки — это результат применения Gradle определённого набора правил для объединения настроек, кода и ресурсов, настроенных в типах сборки и вариантах продукта. Хотя вы не настраиваете варианты сборки напрямую, вы настраиваете типы сборки и варианты продукта, которые их формируют.
Например, вариант продукта «demo» может определять определённые функции и требования к устройству, такие как собственный исходный код, ресурсы и минимальные уровни API, в то время как тип сборки «debug» применяет другие настройки сборки и упаковки, такие как параметры отладки и ключи подписи. Вариант сборки, объединяющий эти два варианта, называется версией «demoDebug» вашего приложения и включает в себя комбинацию конфигураций и ресурсов, входящих в вариант продукта «demo», тип сборки «debug» и набор main/
source».
Настроить типы сборки
Вы можете создавать и настраивать типы сборки внутри блока android
файла build.gradle.kts
уровня модуля. При создании нового модуля Android Studio автоматически создаёт типы сборки debug и release. Хотя тип сборки debug не отображается в файле конфигурации сборки, Android Studio настраивает его с помощью debuggable true
. Это позволяет отлаживать приложение на защищённых устройствах Android и настраивать подпись приложения с помощью универсального хранилища ключей отладки.
Вы можете добавить тип сборки отладки в свою конфигурацию, если хотите добавить или изменить определённые параметры. В следующем примере указывается applicationIdSuffix
для типа сборки отладки и настраивается тип сборки «Staging», который инициализируется с использованием настроек из типа сборки отладки:
Котлин
android { defaultConfig { manifestPlaceholders["hostName"] = "www.example.com" ... } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } getByName("debug") { applicationIdSuffix = ".debug" isDebuggable = true } /** * The `initWith` property lets you copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ create("staging") { initWith(getByName("debug")) manifestPlaceholders["hostName"] = "internal.example.com" applicationIdSuffix = ".debugStaging" } } }
Круто
android { defaultConfig { manifestPlaceholders = [hostName:"www.example.com"] ... } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" debuggable true } /** * The `initWith` property lets you copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ staging { initWith debug manifestPlaceholders = [hostName:"internal.example.com"] applicationIdSuffix ".debugStaging" } } }
Примечание: При внесении изменений в файл конфигурации сборки Android Studio требует синхронизировать ваш проект с новой конфигурацией. Чтобы синхронизировать проект, нажмите «Синхронизировать сейчас» на панели уведомлений, которая появляется при внесении изменений, или нажмите «Синхронизировать проект». на панели инструментов. Если Android Studio обнаружит какие-либо ошибки в вашей конфигурации, появится окно «Сообщения» с описанием проблемы.
Чтобы узнать больше обо всех свойствах, которые можно настроить с помощью типов сборки, прочтите справочник BuildType
.
Настройте вкусы продукта
Создание вариантов продукта аналогично созданию типов сборки. Добавьте варианты продукта в блок productFlavors
конфигурации сборки и включите необходимые настройки. Варианты продукта поддерживают те же свойства, что и defaultConfig
, поскольку defaultConfig
фактически принадлежит классу ProductFlavor
. Это означает, что вы можете указать базовую конфигурацию для всех вариантов в блоке defaultConfig
, и каждый вариант может изменить любое из этих значений по умолчанию, например, applicationId
. Чтобы узнать больше об идентификаторе приложения, прочтите статью Установка идентификатора приложения .
Примечание: Вам по-прежнему необходимо указать имя пакета с помощью атрибута package
в файле main/
manifest. Это имя пакета также необходимо использовать в исходном коде для ссылки на класс R
или для разрешения любых относительных действий или регистрации сервисов. Это позволяет использовать applicationId
для присвоения каждому продукту уникального идентификатора для упаковки и распространения без необходимости изменения исходного кода.
Все вкусы должны принадлежать именованному измерению вкусов, представляющему собой группу вкусов продукта. Необходимо назначить все вкусы измерению вкусов, иначе возникнет следующая ошибка сборки.
Error: All flavors must now belong to a named flavor dimension. The flavor 'flavor_name' is not assigned to a flavor dimension.
Если данный модуль определяет только одно измерение разновидности, плагин Android Gradle автоматически назначает все разновидности модуля этому измерению.
Следующий пример кода создаёт измерение разновидности с именем «version» и добавляет разновидности продукта «demo» и «full». Эти разновидности имеют собственные applicationIdSuffix
и versionNameSuffix
:
Котлин
android { ... defaultConfig {...} buildTypes { getByName("debug"){...} getByName("release"){...} } // Specifies one flavor dimension. flavorDimensions += "version" productFlavors { create("demo") { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension = "version" applicationIdSuffix = ".demo" versionNameSuffix = "-demo" } create("full") { dimension = "version" applicationIdSuffix = ".full" versionNameSuffix = "-full" } } }
Круто
android { ... defaultConfig {...} buildTypes { debug{...} release{...} } // Specifies one flavor dimension. flavorDimensions "version" productFlavors { demo { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension "version" applicationIdSuffix ".demo" versionNameSuffix "-demo" } full { dimension "version" applicationIdSuffix ".full" versionNameSuffix "-full" } } }
Примечание: Если у вас есть устаревшее приложение (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, для распространения вашего приложения с поддержкой нескольких APK в Google Play назначьте всем вариантам одинаковое значение applicationId
и укажите для каждого варианта свой versionCode
. Чтобы распространять разные варианты приложения как отдельные приложения в Google Play, необходимо назначить каждому варианту свой applicationId
.
После создания и настройки вариантов продукта нажмите кнопку «Синхронизировать сейчас» на панели уведомлений. После завершения синхронизации Gradle автоматически создаст варианты сборки на основе ваших типов сборки и вариантов продукта, присваивая им имена в соответствии с <product-flavor><Build-Type>
. Например, если вы создали варианты продукта «demo» и «full» и сохранили типы сборки по умолчанию «debug» и «release», Gradle создаст следующие варианты сборки:
-
demoDebug
-
demoRelease
-
fullDebug
-
fullRelease
Чтобы выбрать вариант сборки для сборки и запуска, перейдите в раздел «Сборка» > «Выбрать вариант сборки» и выберите нужный вариант сборки в меню. Чтобы начать настраивать каждый вариант сборки, добавляя собственные функции и ресурсы, вам необходимо создать и управлять исходными наборами , как описано на этой странице.
Измените идентификатор приложения для вариантов сборки
При сборке APK-файла или AAB-файла для вашего приложения инструменты сборки присваивают приложению идентификатор приложения, указанный в блоке defaultConfig
файла build.gradle.kts
, как показано в следующем примере. Однако, если вы хотите создать разные версии приложения, которые будут отображаться в Google Play Store как отдельные версии, например, «бесплатная» и «профессиональная», вам необходимо создать отдельные варианты сборки с разными идентификаторами приложения.
В этом случае определите каждый вариант сборки как отдельный вариант продукта . Для каждого варианта в блоке productFlavors
можно переопределить свойство applicationId
или вместо этого добавить сегмент к идентификатору приложения по умолчанию с помощью applicationIdSuffix
, как показано здесь:
Котлин
android { defaultConfig { applicationId = "com.example.myapp" } productFlavors { create("free") { applicationIdSuffix = ".free" } create("pro") { applicationIdSuffix = ".pro" } } }
Круто
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } }
Таким образом, идентификатор приложения для «бесплатной» версии продукта будет «com.example.myapp.free».
Вы также можете использовать applicationIdSuffix
для добавления сегмента на основе типа вашей сборки , как показано здесь:
Котлин
android { ... buildTypes { getByName("debug") { applicationIdSuffix = ".debug" } } }
Круто
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Поскольку Gradle применяет конфигурацию типа сборки после версии продукта, идентификатор приложения для варианта сборки «free debug» — «com.example.myapp.free.debug». Это полезно, когда вы хотите иметь и отладочную, и релизную сборки на одном устройстве, поскольку два приложения не могут иметь одинаковый идентификатор приложения.
Если у вас есть устаревшее приложение (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, и вы хотите использовать один и тот же список приложений для распространения нескольких APK, каждый из которых ориентирован на различную конфигурацию устройства, например, на уровень API, то необходимо использовать один и тот же идентификатор приложения для каждого варианта сборки, но присвоить каждому APK свойversionCode
. Подробнее см. в статье «Поддержка нескольких APK» . Публикация с помощью AAB не затрагивается, поскольку в ней используется один артефакт с одним кодом версии и идентификатором приложения по умолчанию. Совет: если вам нужно указать идентификатор приложения в файле манифеста, вы можете использовать плейсхолдер ${applicationId}
в любом атрибуте манифеста. Во время сборки Gradle заменяет этот тег фактическим идентификатором приложения. Подробнее см. в разделе Внедрение переменных сборки в манифест .
Объедините несколько вкусов продукта с различными вкусовыми параметрами
В некоторых случаях может потребоваться объединить конфигурации из разных версий продукта. Например, можно создать разные конфигурации для «полной» и «демонстрационной» версий продукта на основе уровня API. Для этого плагин Android Gradle позволяет создавать несколько групп версий продукта в качестве измерений.
При сборке приложения Gradle объединяет конфигурацию вкуса продукта из каждого указанного вами измерения вкуса с конфигурацией типа сборки для создания финального варианта сборки. Gradle не объединяет вкусы продукта, принадлежащие одному измерению вкуса.
В следующем примере кода свойство flavorDimensions
используется для создания измерения вкуса «mode» для группировки вкусов продукта «full» и «demo», а также измерения вкуса «api» для группировки конфигураций вкусов продукта на основе уровня API:
Котлин
android { ... buildTypes { getByName("debug") {...} getByName("release") {...} } // Specifies the flavor dimensions you want to use. The order in which you // list the dimensions determines their priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions += listOf("api", "mode") productFlavors { create("demo") { // Assigns this product flavor to the "mode" flavor dimension. dimension = "mode" ... } create("full") { dimension = "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property, with the first dimension having a higher // priority than the second, and so on. create("minApi24") { dimension = "api" minSdk = 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. versionCode = 30000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi24" ... } create("minApi23") { dimension = "api" minSdk = 23 versionCode = 20000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi23" ... } create("minApi21") { dimension = "api" minSdk = 21 versionCode = 10000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi21" ... } } } ...
Круто
android { ... buildTypes { debug {...} release {...} } // Specifies the flavor dimensions you want to use. The order in which you // list the dimensions determines their priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions "api", "mode" productFlavors { demo { // Assigns this product flavor to the "mode" flavor dimension. dimension "mode" ... } full { dimension "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property, with the first dimension having a higher // priority than the second, and so on. minApi24 { dimension "api" minSdkVersion 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. versionCode 30000 + android.defaultConfig.versionCode versionNameSuffix "-minApi24" ... } minApi23 { dimension "api" minSdkVersion 23 versionCode 20000 + android.defaultConfig.versionCode versionNameSuffix "-minApi23" ... } minApi21 { dimension "api" minSdkVersion 21 versionCode 10000 + android.defaultConfig.versionCode versionNameSuffix "-minApi21" ... } } } ...
Количество вариантов сборки, создаваемых Gradle, равно произведению количества вариантов в каждом измерении вариантов и количества настроенных вами типов сборки. Когда Gradle присваивает имя каждому варианту сборки или соответствующим артефактам, сначала отображаются варианты продукта, относящиеся к измерению вариантов с более высоким приоритетом, затем — варианты из измерений с более низким приоритетом, а затем — тип сборки.
Используя предыдущую конфигурацию сборки в качестве примера, Gradle создает в общей сложности 12 вариантов сборки со следующей схемой именования:
- Вариант сборки:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
- Соответствующий APK:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
- Например,
- Вариант сборки:
minApi24DemoDebug
- Соответствующий APK:
app-minApi24-demo-debug.apk
Помимо каталогов исходных наборов, которые можно создать для каждого варианта продукта и варианта сборки, вы также можете создать каталоги исходных наборов для каждой комбинации вариантов продукта. Например, вы можете создать и добавить исходные коды Java в каталог src/demoMinApi24/java/
, и Gradle будет использовать эти исходные коды только при сборке варианта, объединяющего эти два варианта продукта.
Исходные наборы, создаваемые для комбинаций вкусов продуктов, имеют более высокий приоритет, чем исходные наборы, принадлежащие каждому отдельному вкусу продукта. Чтобы узнать больше об исходных наборах и о том, как Gradle объединяет ресурсы, прочтите раздел о создании исходных наборов .
Варианты фильтров
Gradle создаёт варианты сборки для каждой возможной комбинации вариантов продукта и типов сборки, которые вы настраиваете. Однако некоторые варианты сборки могут быть вам не нужны или не имеют смысла в контексте вашего проекта. Чтобы удалить определённые конфигурации вариантов сборки, создайте фильтр вариантов в файле build.gradle.kts
на уровне модуля.
Используя конфигурацию сборки из предыдущего раздела в качестве примера, предположим, что вы планируете поддерживать только API уровня 23 и выше для демо-версии приложения. Вы можете использовать блок variantFilter
для фильтрации всех конфигураций вариантов сборки, сочетающих версии продукта «minApi21» и «demo»:
Котлин
android { ... buildTypes {...} flavorDimensions += listOf("api", "mode") productFlavors { create("demo") {...} create("full") {...} create("minApi24") {...} create("minApi23") {...} create("minApi21") {...} } } androidComponents { beforeVariants { variantBuilder -> // To check for a certain build type, use variantBuilder.buildType == "<buildType>" if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) { // Gradle ignores any variants that satisfy the conditions above. variantBuilder.enable = false } } } ...
Круто
android { ... buildTypes {...} flavorDimensions "api", "mode" productFlavors { demo {...} full {...} minApi24 {...} minApi23 {...} minApi21 {...} } variantFilter { variant -> def names = variant.flavors*.name // To check for a certain build type, use variant.buildType.name == "<buildType>" if (names.contains("minApi21") && names.contains("demo")) { // Gradle ignores any variants that satisfy the conditions above. setIgnore(true) } } } ...
После добавления фильтра вариантов в конфигурацию сборки и нажатия кнопки «Синхронизировать сейчас» на панели уведомлений Gradle будет игнорировать все варианты сборки, соответствующие заданным вами условиям. Варианты сборки больше не отображаются в меню при нажатии «Сборка» > «Выбрать вариант сборки» в строке меню или в разделе «Варианты сборки». на панели окна инструментов.
Создать исходные наборы
По умолчанию Android Studio создаёт набор исходных файлов main/
и каталоги для всего, что вы хотите использовать во всех вариантах сборки. Однако вы можете создать новые наборы исходных файлов, чтобы точно контролировать, какие файлы Gradle компилирует и упаковывает для определённых типов сборок, вариантов продукта, комбинаций вариантов продукта (при использовании параметров вариантов ) и вариантов сборки.
Например, вы можете определить базовую функциональность в исходном наборе main/
и использовать исходные наборы product flavor, чтобы изменить фирменное оформление вашего приложения для разных клиентов, или включить специальные разрешения и функциональность ведения журнала только для вариантов сборки, которые используют тип сборки debug.
Gradle ожидает, что файлы и каталоги исходного набора будут организованы определённым образом, аналогично исходному набору main/
. Например, Gradle ожидает, что файлы классов Kotlin или Java, специфичные для вашего типа сборки «debug», будут расположены в каталогах src/debug/kotlin/
или src/debug/java/
.
Плагин Android Gradle предоставляет полезную задачу Gradle, которая показывает, как организовать файлы для каждого типа сборки, варианта продукта и варианта сборки. Например, следующий пример вывода задачи описывает, где Gradle ожидает найти определенные файлы для типа сборки «debug»:
------------------------------------------------------------ Project :app ------------------------------------------------------------ ... debug ---- Compile configuration: debugCompile build.gradle name: android.sourceSets.debug Java sources: [app/src/debug/java] Kotlin sources: [app/src/debug/kotlin, app/src/debug/java] Manifest file: app/src/debug/AndroidManifest.xml Android resources: [app/src/debug/res] Assets: [app/src/debug/assets] AIDL sources: [app/src/debug/aidl] RenderScript sources: [app/src/debug/rs] JNI sources: [app/src/debug/jni] JNI libraries: [app/src/debug/jniLibs] Java-style resources: [app/src/debug/resources]
Чтобы просмотреть этот вывод, выполните следующие действия:
- Нажмите Gradle на панели инструментов.
Перейдите в MyApplication > Tasks > android и дважды щелкните sourceSets .
Чтобы увидеть папку «Задачи» , необходимо разрешить Gradle создать список задач во время синхронизации. Для этого выполните следующие действия:
- Нажмите Файл > Настройки > Экспериментальные ( Android Studio > Настройки > Экспериментальные в macOS).
- Снимите флажок Не формировать список задач Gradle во время синхронизации Gradle .
- После того как Gradle выполнит задачу, откроется окно «Выполнить» для отображения вывода.
Примечание: выходные данные задачи также показывают, как организовать исходные наборы для файлов, которые вы хотите использовать для запуска тестов вашего приложения, например, исходные наборы тестирования test/
и androidTest/
.
При создании нового варианта сборки Android Studio не создаёт каталоги исходных наборов автоматически, но предлагает несколько вариантов. Например, чтобы создать только каталог java/
для типа сборки «debug»:
- Откройте панель «Проект» и выберите пункт «Проект» в меню в верхней части панели.
- Перейдите в
MyProject/app/src/
. - Щелкните правой кнопкой мыши по каталогу
src
и выберите Создать > Каталог . - В меню Gradle Source Sets выберите full/java .
- Нажмите Enter .
Android Studio создаёт каталог с исходным набором для вашего типа отладочной сборки, а затем внутри него создаёт каталог java/
. Кроме того, Android Studio может создавать эти каталоги автоматически при добавлении нового файла в проект для определённого варианта сборки.
Например, чтобы создать XML-файл значений для типа сборки «отладка»:
- На панели «Проект» щелкните правой кнопкой мыши каталог
src
и выберите «Создать» > «XML» > «XML-файл значений» . - Введите имя XML-файла или оставьте имя по умолчанию.
- В меню рядом с пунктом Target Source Set выберите пункт debug .
- Нажмите кнопку Готово .
Поскольку в качестве целевого исходного набора был указан тип сборки «debug», Android Studio автоматически создаёт необходимые каталоги при создании XML-файла. Результирующая структура каталогов выглядит как на рисунке 1.

Рисунок 1. Новые каталоги исходного набора для типа сборки «отладка».
Активные наборы исходных кодов отмечены зелёным индикатором на значке, указывающим на их активность. Набор исходных кодов debug
имеет суффикс [main]
указывающий на то, что он будет объединён с main
набором исходных кодов.
Используя ту же процедуру, вы также можете создать каталоги исходных наборов для различных вариантов продукта, например, src/demo/
, и вариантов сборки, например, src/demoDebug/
. Кроме того, вы можете создать тестовые исходные наборы, предназначенные для конкретных вариантов сборки, например, src/androidTestDemoDebug/
. Подробнее см. в статье о тестовых исходных наборах .
Изменить конфигурации исходного набора по умолчанию
Если у вас есть источники, которые не организованы в структуру файлов исходного набора по умолчанию, ожидаемую Gradle, как описано в предыдущем разделе о создании исходных наборов , вы можете использовать блок sourceSets
, чтобы изменить место, где Gradle ищет файлы для каждого компонента исходного набора.
Блок sourceSets
должен находиться в блоке android
. Вам не нужно перемещать исходные файлы; достаточно указать Gradle путь(и) относительно файла build.gradle.kts
на уровне модуля, где Gradle сможет найти файлы для каждого компонента исходного набора. Чтобы узнать, какие компоненты можно настроить и можно ли сопоставить их с несколькими файлами или каталогами, см. справочник по API плагина Android Gradle .
Следующий пример кода сопоставляет источники из каталога app/other/
с определенными компонентами main
набора источников и изменяет корневой каталог набора источников androidTest
:
Котлин
android { ... // Encapsulates configurations for the main source set. sourceSets.getByName("main") { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.setSrcDirs(listOf("other/java")) // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you receive an // error when merging resources. The default directory is 'src/main/res'. res.setSrcDirs(listOf("other/res1", "other/res2")) // Note: Avoid specifying a directory that is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // Specify either only the root 'other/res1' directory or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile("other/AndroidManifest.xml") ... } // Create additional blocks to configure other source sets. sourceSets.getByName("androidTest") { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot("src/tests") ... } } ...
Круто
android { ... sourceSets { // Encapsulates configurations for the main source set. main { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.srcDirs = ['other/java'] // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you receive an // error when merging resources. The default directory is 'src/main/res'. res.srcDirs = ['other/res1', 'other/res2'] // Note: Avoid specifying a directory that is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // Specify either only the root 'other/res1' directory or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile 'other/AndroidManifest.xml' ... } // Create additional blocks to configure other source sets. androidTest { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot 'src/tests' ... } } } ...
Обратите внимание, что исходный каталог может принадлежать только одному набору исходных файлов. Например, нельзя использовать одни и те же исходные файлы тестов одновременно в наборах исходных файлов test
и androidTest
. Это связано с тем, что Android Studio создаёт отдельные модули IntelliJ для каждого набора исходных файлов и не поддерживает дублирование корневых каталогов контента в разных наборах исходных файлов.
Сборка с исходными наборами
Вы можете использовать каталоги исходных наборов для хранения кода и ресурсов, которые вы хотите упаковать только с определёнными конфигурациями. Например, если вы собираете вариант сборки «demoDebug», который представляет собой кросс-произведение варианта продукта «demo» и типа сборки «debug», Gradle просматривает эти каталоги и присваивает им следующий приоритет:
-
src/demoDebug/
(исходный набор вариантов сборки) -
src/debug/
(исходный набор типа сборки) -
src/demo/
(исходный набор вкусов продукта) -
src/main/
(основной исходный набор)
Исходные наборы, созданные для комбинаций вкусов продукта, должны включать все параметры вкуса. Например, исходный набор для варианта сборки должен представлять собой комбинацию типа сборки и всех параметров вкуса. Объединение кода и ресурсов, включающих папки, охватывающие несколько, но не все параметры вкуса, не поддерживается.
При объединении нескольких вкусов продуктов приоритет между ними определяется измерением вкуса, к которому они относятся. При перечислении измерений вкуса с помощью свойства android.flavorDimensions
вкусы продуктов, принадлежащие первому указанному измерению вкуса, имеют более высокий приоритет, чем те, которые принадлежат второму измерению вкуса, и так далее. Кроме того, исходные наборы, создаваемые для комбинаций вкусов продуктов, имеют более высокий приоритет, чем исходные наборы, принадлежащие отдельному вкусу продукта.
Порядок приоритетов определяет, какой исходный набор имеет более высокий приоритет при объединении кода и ресурсов Gradle. Поскольку каталог исходного набора demoDebug/
, вероятно, содержит файлы, специфичные для этого варианта сборки, если в demoDebug/
есть файл, который также определён в debug/
, Gradle использует этот файл из исходного набора demoDebug/
. Аналогично, Gradle присваивает файлам в исходных наборах типа сборки и разновидности продукта более высокий приоритет, чем тем же файлам в main/
. Gradle учитывает этот порядок приоритетов при применении следующих правил сборки:
- Весь исходный код в каталогах
kotlin/
илиjava/
компилируется вместе для создания единого выходного файла.Примечание: Для данного варианта сборки Gradle выдаёт ошибку сборки, если обнаруживает два или более каталогов исходного набора, в которых определён один и тот же класс Kotlin или Java. Например, при сборке отладочного приложения невозможно определить одновременно
src/debug/Utility.kt
иsrc/main/Utility.kt
, поскольку Gradle просматривает оба этих каталога в процессе сборки и выдаёт ошибку «дубликат класса». Если вам нужны разные версииUtility.kt
для разных типов сборки, каждый тип сборки должен определить свою версию файла и не включать её в исходный наборmain/
. - Манифесты объединяются в один. Приоритет задаётся в том же порядке, что и в списке в предыдущем примере. То есть настройки манифеста для типа сборки переопределяют настройки манифеста для версии продукта и так далее. Подробнее см. в статье об объединении манифестов .
- Файлы в каталогах
values/
объединяются. Если два файла имеют одинаковое имя, например, два файлаstrings.xml
, приоритет отдаётся в том же порядке, что и в списке в предыдущем примере. То есть значения, определённые в файле исходного набора типа сборки, переопределяют значения, определённые в том же файле в версии продукта, и так далее. - Ресурсы в каталогах
res/
иasset/
упакованы вместе. Если в двух или более исходных наборах определены ресурсы с одинаковым именем, приоритет отдаётся в том же порядке, что и в списке в предыдущем примере. - Gradle присваивает ресурсам и манифестам, включенным в зависимости от модулей библиотеки, самый низкий приоритет при сборке приложения.
Объявить зависимости
Чтобы настроить зависимость для определенного варианта сборки или исходного набора тестирования , добавьте префикс имени варианта сборки или исходного набора тестирования перед ключевым словом Implementation
, как показано в следующем примере:
Котлин
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. "freeImplementation"(project(":mylibrary")) // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1") }
Круто
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. freeImplementation project(":mylibrary") // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1' }
Дополнительные сведения о настройке зависимостей см. в разделе Добавление зависимостей сборки .
Используйте управление зависимостями с учетом вариантов
Плагин Gradle для Android версии 3.0.0 и выше включает новый механизм зависимостей, который автоматически подбирает варианты при использовании библиотеки. Это означает, что debug
вариант приложения автоматически использует debug
вариант библиотеки и т. д. Это также работает при использовании разновидностей: вариант freeDebug
приложения будет использовать вариант freeDebug
библиотеки.
Чтобы плагин точно сопоставлял варианты, вам необходимо предоставить соответствующие резервные варианты , как описано в следующем разделе, для случаев, когда прямое сопоставление невозможно.
Например, предположим, что ваше приложение настраивает тип сборки под названием «staging», но одна из его зависимостей библиотек не настроена. Когда плагин попытается собрать версию «staging» вашего приложения, он не будет знать, какую версию библиотеки использовать, и вы увидите сообщение об ошибке, похожее на следующее:
Error:Failed to resolve: Could not resolve project :mylibrary. Required by: project :app
Устранение ошибок сборки, связанных с сопоставлением вариантов
Плагин включает элементы DSL, которые помогут вам контролировать, как Gradle разрешает ситуации, в которых прямое соответствие вариантов между приложением и зависимостью невозможно.
Ниже приведен список проблем, связанных с сопоставлением зависимостей с учетом вариантов, и способов их решения с использованием свойств DSL:Ваше приложение включает тип сборки, которого нет в зависимости от библиотеки.
Например, ваше приложение включает тип сборки «Staging», но зависимость включает только типы сборки «Debug» и «Release».
Обратите внимание, что если зависимость библиотеки включает тип сборки, которого нет в вашем приложении, это не является проблемой. Это связано с тем, что плагин никогда не запрашивает этот тип сборки из зависимости.
Используйте
matchingFallbacks
, чтобы указать альтернативные соответствия для заданного типа сборки, как показано здесь:Котлин
// In the app's build.gradle.kts file. android { buildTypes { getByName("debug") {} getByName("release") {} create("staging") { // Specifies a sorted list of fallback build types that the // plugin can try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks += listOf("debug", "qa", "release") } } }
Круто
// In the app's build.gradle file. android { buildTypes { debug {} release {} staging { // Specifies a sorted list of fallback build types that the // plugin can try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks = ['debug', 'qa', 'release'] } } }
Для заданного измерения вкуса, которое существует как в приложении, так и в его библиотечной зависимости, ваше приложение включает в себя вкусы, которых нет в библиотеке.
Например, и ваше приложение, и его зависимости от библиотеки включают измерение «уровень». Однако измерение «уровень» в приложении включает «бесплатные» и «платные» варианты, а зависимость включает только «демонстрационные» и «платные» варианты для того же измерения.
Обратите внимание, что для заданного измерения «разновидность», существующего как в приложении, так и в его библиотечных зависимостях, не возникает проблем, если библиотека включает разновидность продукта, которой нет в вашем приложении. Это связано с тем, что плагин никогда не запрашивает эту разновидность из зависимости.
Используйте
matchingFallbacks
, чтобы указать альтернативные соответствия для «бесплатной» версии продукта приложения, как показано здесь:Котлин
// In the app's build.gradle.kts file. android { defaultConfig{ // Don't configure matchingFallbacks in the defaultConfig block. // Instead, specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions += "tier" productFlavors { create("paid") { dimension = "tier" // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } create("free") { dimension = "tier" // Specifies a sorted list of fallback flavors that the plugin // can try to use when a dependency's matching dimension does // not include a "free" flavor. Specify as many // fallbacks as you like; the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks += listOf("demo", "trial") } } }
Круто
// In the app's build.gradle file. android { defaultConfig{ // Don't configure matchingFallbacks in the defaultConfig block. // Instead, specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions 'tier' productFlavors { paid { dimension 'tier' // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } free { dimension 'tier' // Specifies a sorted list of fallback flavors that the plugin // can try to use when a dependency's matching dimension does // not include a "free" flavor. Specify as many // fallbacks as you like; the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks = ['demo', 'trial'] } } }
Зависимость от библиотеки включает в себя измерение вкуса, которого нет в вашем приложении.
Например, зависимость библиотеки включает варианты для измерения «minApi», но ваше приложение включает варианты только для измерения «tier». Когда вы хотите собрать версию приложения «freeDebug», плагин не знает, какую версию зависимости использовать — «minApi23Debug» или «minApi18Debug».
Обратите внимание, что если ваше приложение включает измерение типа «аромат», которого нет в зависимости от библиотеки, это не будет проблемой. Это связано с тем, что плагин сопоставляет разновидности только тех измерений, которые есть в зависимости. Например, если зависимость не включает измерение для ABI, версия вашего приложения «freeX86Debug» будет использовать версию «freeDebug» этой зависимости.
Используйте
missingDimensionStrategy
в блокеdefaultConfig
, чтобы указать вариант по умолчанию, который плагин будет выбирать из каждого отсутствующего измерения, как показано в следующем примере. Вы также можете переопределить свой выбор в блокеproductFlavors
, чтобы для каждого варианта можно было задать отдельную стратегию сопоставления для отсутствующего измерения.Котлин
// In the app's build.gradle.kts file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin can try to use from // a given dimension. This tells the plugin to select the "minApi18" flavor // when encountering a dependency that includes a "minApi" dimension. // You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy("minApi", "minApi18", "minApi23") // Specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy("abi", "x86", "arm64") } flavorDimensions += "tier" productFlavors { create("free") { dimension = "tier" // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the "minApi" dimension. missingDimensionStrategy("minApi", "minApi23", "minApi18") } create("paid") {} } }
Круто
// In the app's build.gradle file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin can try to use from // a given dimension. This tells the plugin to select the "minApi18" flavor // when encountering a dependency that includes a "minApi" dimension. // You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy 'minApi', 'minApi18', 'minApi23' // Specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy 'abi', 'x86', 'arm64' } flavorDimensions 'tier' productFlavors { free { dimension 'tier' // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the 'minApi' dimension. missingDimensionStrategy 'minApi', 'minApi23', 'minApi18' } paid {} } }
Для получения дополнительной информации см. matchingFallbacks
и missingDimensionStrategy
в справочнике DSL плагина Android Gradle.
Настройте параметры подписи
Gradle не подписывает APK или AAB вашей релизной сборки, если вы явно не указали конфигурацию подписи для этой сборки. Если у вас ещё нет ключа подписи, сгенерируйте ключ загрузки и хранилище ключей с помощью Android Studio.
Чтобы вручную настроить конфигурации подписи для вашего типа сборки релиза с помощью конфигураций сборки Gradle:
- Создайте хранилище ключей. Хранилище ключей — это двоичный файл, содержащий набор закрытых ключей. Храните хранилище ключей в безопасном и надёжном месте.
- Создайте закрытый ключ. Закрытый ключ используется для подписи вашего приложения при его распространении и никогда не включается в комплект поставки и не передается неавторизованным третьим лицам.
Добавьте конфигурацию подписи в файл
build.gradle.kts
на уровне модуля:Котлин
... android { ... defaultConfig {...} signingConfigs { create("release") { storeFile = file("myreleasekey.keystore") storePassword = "password" keyAlias = "MyReleaseKey" keyPassword = "password" } } buildTypes { getByName("release") { ... signingConfig = signingConfigs.getByName("release") } } }
Круто
... android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
Примечание: Включение паролей для ключа выпуска и хранилища ключей в файл сборки не является хорошей практикой безопасности. Вместо этого настройте файл сборки так, чтобы эти пароли были получены из переменных среды, или включите запрос этих паролей в процессе сборки.
Чтобы получить эти пароли из переменных среды:
Котлин
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Круто
storePassword System.getenv("KSTOREPWD") keyPassword System.getenv("KEYPWD")
В качестве альтернативы вы можете загрузить хранилище ключей из локального файла свойств. Из соображений безопасности не добавляйте этот файл в систему управления версиями. Вместо этого настройте его локально для каждого разработчика. Подробнее см. в статье «Удаление информации о подписи из файлов сборки» .
После завершения этого процесса вы сможете распространять свое приложение и публиковать его в Google Play.
Внимание: Храните хранилище ключей и закрытый ключ в безопасном месте и убедитесь, что у вас есть их резервные копии. Если вы используете функцию подписи приложений в Play App Signing и потеряете ключ загрузки, вы можете запросить его сброс через Play Console. Если вы публикуете приложение без функции подписи приложений в Play App Signing (для приложений, созданных до августа 2021 года) и потеряете ключ подписи приложения, вы не сможете публиковать обновления своего приложения, поскольку все версии приложения должны всегда подписывать одним и тем же ключом.
Подписание приложений Wear OS
При публикации приложений Wear OS APK-файл часов и (опционально) APK-файл телефона должны быть подписаны одним и тем же ключом. Подробнее об упаковке и подписании приложений Wear OS см. в разделе Упаковка и распространение приложений Wear .