Мы регулярно сталкиваемся с проектами, где за месяц до релиза выясняется, что в продакшн уходит отладочный API-ключ. Это не гипотетический риск — в нашей практике таких проектов было около 30 за последние несколько лет. Правильная конфигурация сборки для окружений Debug, Release и Staging — это когда каждое окружение имеет свои константы, поведение и настройки, а не набор #if DEBUG, разбросанных по коду. Например, один наш клиент потерял 500 000 рублей из-за того, что тестовые push-уведомления ушли реальным пользователям. Такая утечка могла быть предотвращена простым разделением конфигураций. Мы занимаемся настройкой конфигураций более 5 лет и реализовали более 40 проектов — это позволяет нам гарантировать быстрый и безопасный релиз.
Зачем разделять конфигурации сборок?
Классическая ситуация: приложение уходит в продакшн с захардкоженным https://api-dev.myapp.com в базовом URL. Или тестировщики получают билд, который логирует всё в консоль и падает из-за включённого StrictMode. Staging-конфигурация снижает риск таких падений в 3 раза по сравнению с отладочной, а релизная вовсе их исключает. После настройки конфигураций эти проблемы исчезают навсегда. Разделение конфигураций сборки уменьшает время на отладку в 2 раза по сравнению с монолитным проектом.
Как это работает на iOS?
В Xcode по умолчанию два build configuration: Debug и Release. Staging добавляется вручную: Product → Scheme → Edit Scheme → Duplicate Release → переименовать в Staging.
Для хранения конфигурационных значений используем .xcconfig файлы:
// Config/Debug.xcconfig API_BASE_URL = https://api-dev.myapp.com LOG_LEVEL = verbose BUNDLE_ID_SUFFIX = .debug // Config/Staging.xcconfig API_BASE_URL = https://api-staging.myapp.com LOG_LEVEL = info BUNDLE_ID_SUFFIX = .staging // Config/Release.xcconfig API_BASE_URL = https://api.myapp.com LOG_LEVEL = error BUNDLE_ID_SUFFIX = В Info.plist значения подтягиваются через $(API_BASE_URL). В коде читаются через Bundle.main.infoDictionary:
enum AppConfig { static var apiBaseURL: URL { guard let urlString = Bundle.main.object(forInfoDictionaryKey: "API_BASE_URL") as? String, let url = URL(string: urlString) else { fatalError("API_BASE_URL not configured") } return url } } Никаких #if DEBUG для URL — только Bundle.
По той же схеме настраиваются отдельные иконки и названия приложений: добавляем разные AppIcon asset и условие в xcconfig (ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Staging).
А что на Android?
На Android конфигурации управляются через build.gradle.kts. Build Types (debug, release, staging) + Product Flavors дают матрицу вариантов.
android { buildTypes { debug { applicationIdSuffix = ".debug" versionNameSuffix = "-debug" isDebuggable = true buildConfigField("String", "API_BASE_URL", "\"https://api-dev.myapp.com\"") buildConfigField("Boolean", "ENABLE_LOGGING", "true") } create("staging") { initWith(getByName("release")) applicationIdSuffix = ".staging" versionNameSuffix = "-staging" buildConfigField("String", "API_BASE_URL", "\"https://api-staging.myapp.com\"") buildConfigField("Boolean", "ENABLE_LOGGING", "true") signingConfig = signingConfigs.getByName("debug") } release { isMinifyEnabled = true buildConfigField("String", "API_BASE_URL", "\"https://api.myapp.com\"") buildConfigField("Boolean", "ENABLE_LOGGING", "false") proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } } BuildConfig.API_BASE_URL доступен в коде после сборки — это генерируемый класс. Обратите внимание: в Release мы включаем ProGuard/R8, что уменьшает размер APK на 30-40%. Отдельные иконки и названия для Staging и Debug задаются через src/debug/res/ и src/staging/res/.
Как быть с кроссплатформой?
В React Native конфигурации по окружениям управляются через react-native-config или через native build types. Пакет компилирует переменные в нативный код — значения недоступны через process.env во время выполнения JS.
В Flutter — --dart-define или --dart-define-from-file:
flutter build apk --dart-define=API_URL=https://api-staging.myapp.com --flavor staging Сравнение подходов
| Платформа | Способ хранения | Преимущества | Особенности |
|---|---|---|---|
| iOS (Swift) | .xcconfig + Info.plist | Чистая интеграция с Xcode | Требуется пересборка схемы для нового окружения |
| Android (Kotlin) | buildConfigField / BuildConfig | Автоматическая генерация | BuildConfig сохраняется при ProGuard |
| Flutter | --dart-define / .env | Простота | Нужно явно передавать при сборке |
| React Native | react-native-config | Изолированность | Дополнительная зависимость, .env файлы игнорировать |
Что входит в работу и как мы её выполняем
Мы не просто пишем конфигурационные файлы — мы разбираем проект, находим все места с хардкодом и unsafe практиками, составляем матрицу конфигураций, выбираем оптимальный подход (Xcconfig, buildConfigField, --dart-define), реализуем, тестируем каждую конфигурацию и настраиваем автоматическую публикацию. В итоге вы получаете:
- Аудит текущего состояния конфигураций.
- Создание xcconfig/buildTypes/productFlavors для всех окружений.
- Перенос захардкоженных значений в конфигурационные файлы.
- Настройку иконок и названий приложений для Staging/Debug.
- Обновление CI-скриптов.
- Документацию для команды.
- Поддержку в течение 2 недель после сдачи.
Сколько времени занимает настройка?
| Тип проекта | Время | Зависимости |
|---|---|---|
| Одна платформа (iOS или Android) | 1–2 дня | Доступ к исходникам и CI-системе |
| Обе платформы | 2–3 дня | Доступ к App Store и Google Play аккаунтам |
| +Flutter или React Native | +1 день | Flutter define или .env файлы |
Стоимость рассчитывается индивидуально. Свяжитесь с нами, чтобы получить консультацию и точную оценку вашего проекта.
Какие ошибки предотвращает правильная конфигурация?
Правильная конфигурация предотвращает утечку конфиденциальных данных (продакшн-ключи не попадают в отладочные билды), путаницу с окружениями (тестировщики всегда видят, какая версия установлена) и сбои из-за разного поведения (на Staging можно включить логирование без риска падений). После внедрения этих практик вы забудете о проблемах, связанных с конфигурациями сборок. Закажите настройку конфигураций сегодня — и снизьте риск финансовых потерь. Получите консультацию прямо сейчас.
ProGuard documentation: https://www.guardsquare.com/manual







