На этой странице показано, как настроить варианты сборки для создания разных версий вашего приложения из одного проекта, а также как правильно управлять зависимостями и настройками подписи.
Каждый вариант сборки представляет собой отдельную версию вашего приложения, которую вы можете создать. Например, вы можете захотеть создать одну бесплатную версию приложения с ограниченным набором контента и другую платную версию, которая включает в себя больше контента. Вы также можете создавать разные версии приложения, ориентированные на разные устройства, в зависимости от уровня API или других параметров устройства.
Варианты сборки — это результат использования Gradle определенного набора правил для объединения настроек, кода и ресурсов, заданных в типах сборки и вариантах продукта. Хотя вы не настраиваете варианты сборки напрямую, вы настраиваете типы сборки и варианты продукта, которые их формируют.
Например, для демо -версии продукта могут быть указаны определенные функции и требования к устройствам, такие как пользовательский исходный код, ресурсы и минимальные уровни API, в то время как для отладочной версии сборки применяются другие параметры сборки и упаковки, такие как параметры отладки и ключи подписи. Вариант сборки, объединяющий эти два варианта, называется «demoDebug» и включает в себя комбинацию конфигураций и ресурсов, входящих в демо-версию продукта, отладочную версию сборки и main/ исходный набор.
Настройка типов сборки
Вы можете создавать и настраивать типы сборки внутри блока android в файле build.gradle.kts на уровне модуля. При создании нового модуля Android Studio автоматически создает типы сборки debug и release. Хотя тип сборки debug не отображается в файле конфигурации сборки, Android Studio настраивает его с debuggable true . Это позволяет отлаживать приложение на защищенных устройствах Android и настраивать подпись приложения с помощью универсального хранилища ключей отладки.
Вы можете добавить тип сборки «отладка» в свою конфигурацию, если хотите добавить или изменить определенные параметры. В следующем примере указывается applicationIdSuffix для типа сборки «отладка» и настраивается тип сборки «промежуточная», который инициализируется с использованием параметров из типа сборки «отладка»:
Котлин
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/ наборе исходных файлов и использовать наборы исходных файлов для различных вариантов продукта, чтобы изменить фирменную символику вашего приложения для разных клиентов, или включить специальные разрешения и функции логирования только для вариантов сборки, использующих тип сборки 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/ testing .
При создании нового варианта сборки Android Studio не создает каталоги исходного кода автоматически, но предоставляет несколько вариантов для упрощения процесса. Например, чтобы создать только каталог java/ для отладочной сборки, введите:
- Откройте панель «Проект» и выберите пункт «Вид проекта» в меню в верхней части панели.
- Перейдите в папку
MyProject/app/src/. - Щелкните правой кнопкой мыши по каталогу
srcи выберите «Создать» > «Каталог» . - В меню раздела «Наборы исходных файлов Gradle» выберите full/java .
- Нажмите Enter .
Android Studio создает каталог исходного кода для вашего типа сборки отладки, а затем создает внутри него каталог java/ . В качестве альтернативы, Android Studio может создать каталоги автоматически при добавлении нового файла в ваш проект для определенного варианта сборки.
Например, чтобы создать XML-файл со значениями для вашего типа сборки "отладка":
- В панели «Проект» щелкните правой кнопкой мыши каталог
srcи выберите «Создать» > «XML» > «XML-файл значений» . - Введите имя для XML-файла или оставьте имя по умолчанию.
- В меню рядом с пунктом «Набор целевых источников» выберите «Отладка» .
- Нажмите «Готово» .
Поскольку в качестве целевого набора исходных файлов был указан тип сборки "отладка", 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' }
Для получения дополнительной информации о настройке зависимостей см. раздел «Добавление зависимостей сборки» .
Используйте управление зависимостями с учетом вариантов.
В плагине Android Gradle версии 3.0.0 и выше включен новый механизм зависимостей, который автоматически сопоставляет варианты при использовании библиотеки. Это означает, что debug вариант приложения автоматически будет использовать debug вариант библиотеки и так далее. Это также работает при использовании вариантов библиотеки (flavors): freeDebug вариант приложения будет использовать freeDebug вариант библиотеки.
Для точного сопоставления вариантов плагином необходимо указать резервные варианты , как описано в следующем разделе, на случай, когда прямое сопоставление невозможно.
Например, предположим, что в вашем приложении указан тип сборки "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 и потеряли ключ для загрузки, вы можете запросить его сброс через Play Console. Если вы публикуете приложение без функции подписи приложений Play (для приложений, созданных до августа 2021 года) и потеряли ключ подписи приложения, вы не сможете публиковать обновления для своего приложения, поскольку все версии приложения всегда должны подписываться одним и тем же ключом.
Подписание приложений Wear OS
При публикации приложений Wear OS как APK-файл для часов, так и дополнительный APK-файл для телефона должны быть подписаны одним и тем же ключом. Дополнительную информацию об упаковке и подписи приложений Wear OS см. в разделе «Упаковка и распространение приложений Wear» .