Введение
Product flavors в Android позволяют создавать разные варианты приложения из одного проекта, например, бесплатную и платную версии, или версии для разных регионов с уникальными ресурсами, зависимостями и настройками. Это экономит время разработки и упрощает поддержку кодовой базы, так как общий код остаётся в основном исходном наборе, а различия изолируются в папках, специфичных для каждого flavor.
Требования
Перед началом убедитесь, что у вас установлены:
- Android Studio последней версии (рекомендуется Arctic Fox или новее).
- Базовое понимание файлов сборки Gradle в Android.
- Доступ к файлу
build.gradleна уровне модуля приложения (обычноapp/build.gradle).
Пошаговая инструкция
В этом разделе мы настроим два product flavors: free и paid. Каждый будет иметь уникальный package name суффикс и version name.
Шаг 1: Откройте файл build.gradle модуля приложения
В Android Studio в проекте найдите файл build.gradle (Module: app). Обычно он находится в папке app/ или вашего модуля. Откройте его для редактирования. Убедитесь, что редактируете файл уровня модуля, а не корневой файл проекта.
Шаг 2: Добавьте блок productFlavors в конфигурацию android
Внутри блока android { ... } добавьте следующие строки, если их ещё нет:
android {
// ... существующие настройки (compileSdk, defaultConfig и т.д.)
// Указываем измерение (dimension) для flavors. Это обязательно, если используете несколько измерений.
flavorDimensions "version"
productFlavors {
// Определения flavors будут здесь
}
}
Если у вас уже есть flavorDimensions, используйте существующее или добавьте новое. Измерение позволяет группировать flavors, если их несколько (например, "tier" и "region").
Шаг 3: Определите каждый flavor с уникальными параметрами
Внутри productFlavors { ... } добавьте каждый flavor. Пример для free и paid:
productFlavors {
free {
dimension "version"
applicationIdSuffix ".free"
versionNameSuffix "-free"
// Дополнительно: ресурсы или зависимости, специфичные для free
}
paid {
dimension "version"
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
}
dimension— указывает измерение, к которому относится flavor. Обязательно, если определеныflavorDimensions.applicationIdSuffix— добавляет суффикс к package name, чтобы flavors имели уникальные ID (например,com.example.app.free). Без этого flavors с одинаковымapplicationIdне смогут устанавливаться одновременно.versionNameSuffix— добавляет суффикс кversionNameдля отличия в Google Play (например,1.0-free).
Вы можете также задавать другие параметры внутри каждого flavor:
minSdkVersion,targetSdkVersion— переопределить версии SDK.resValue "string", "app_name", "MyApp Free"— определить строковый ресурс, доступный черезR.string.app_name.buildConfigField "String", "API_URL", '"https://api.free.example.com"'— создать константу в классеBuildConfigдля использования в коде.sourceSets— указать кастомные пути к исходным кодам и ресурсам (хотя по умолчанию Gradle ищет вsrc/free/,src/paid/).
Шаг 4: Синхронизируйте проект с Gradle
После внесения изменений нажмите кнопку Sync Now в верхней части редактора файла (появится после редактирования) или выберите File → Sync Project with Gradle Files. Это применит новые настройки. Если есть синтаксические ошибки, они отобразятся в панели Build. Для диагностики можно выполнить в терминале:
./gradlew --refresh-dependencies
Шаг 5: Соберите APK для выбранного flavor
В Android Studio откройте панель Build Variants (обычно слева, в разделе Tool Windows). Вы увидите комбинации flavors и build types. Например, freeDebug, freeRelease, paidDebug, paidRelease.
Чтобы собрать APK:
- Выберите нужный build variant (например,
freeReleaseдля релизной сборки бесплатной версии). - Перейдите в Build → Build Bundle(s) / APK(s) → Build APK(s).
- Готовый APK будет создан в папке
app/build/outputs/apk/free/release/(илиpaid/release/).
Или используйте командную строку (в корне проекта):
# Сборка debug-версии free flavor
./gradlew assembleFreeDebug
# Сборка release-версии paid flavor
./gradlew assemblePaidRelease
Проверка результата
Убедитесь, что flavors работают корректно:
- В панели Build Variants переключайтесь между
freeDebugиpaidDebug. Должны меняться ресурсы, если вы добавили flavor-specific (например, разные иконки вsrc/free/res/иsrc/paid/res/). - Установите оба APK на устройство или эмулятор. Проверьте package name: для
freeflavor должно быть, например,com.example.app.free, а дляpaid—com.example.app.paid. Они не должны конфликтовать. - Запустите приложение для каждого flavor и проверьте наличие уникальных ресурсов или поведения, заданных через
resValueилиbuildConfigField. Например, в коде можно использоватьBuildConfig.API_URL.
Возможные проблемы
- Ошибка: "More than one file was found with OS independent path" — возникает при дублировании ресурсов (например, одинаковых имен файлов) между flavors или с основными ресурсами. Убедитесь, что ресурсы для каждого flavor размещены только в своих папках (
src/free/res/,src/paid/res/) и нет конфликтов. - Конфликт applicationId — если не использовать
applicationIdSuffixили задавать одинаковыйapplicationIdдля всех flavors, они будут иметь одинаковый package name, что недопустимо для одновременной установки. Всегда добавляйте уникальный суффикс или меняйтеapplicationIdполностью. - Отсутствующие зависимости — если flavor требует специфичных библиотек (например, реклама только в free версии), добавьте их в блок
dependenciesвнутри flavor:
Используйте конфигурацииfreeImplementation 'com.google.android.gms:play-services-ads:22.0.0'implementation,apiи т.д., как в основномdependencies. - Проблемы с синхронизацией Gradle — проверьте синтаксис в
build.gradle, особенно скобки и отступы. Если кэш Gradle поврежден, выполните./gradlew cleanили используйте File → Invalidate Caches and Restart в Android Studio. - Flavor-specific код не подхватывается — убедитесь, что Java/Kotlin файлы размещены в правильных исходных наборах:
src/free/java/иsrc/paid/java/. Gradle автоматически включает их при сборке соответствующего flavor. Также проверьте, чтоsourceSetsне переопределены вручную без учёта flavors. - Изменения в flavors не применяются — после редактирования
build.gradleобязательно синхронизируйте проект. Если проблема остаётся, проверьте, не переопределены ли параметры (например,applicationId) вdefaultConfigили других блоках — приоритет имеют flavor-specific настройки.