Настройка конфігурації сборки (Debug, Release, Staging)
Класична ситуація: додаток уходить в продакшн з захардкоженим https://api-dev.myapp.com у базовому URL. Або тестувальники отримують білд, який логує все в консоль та падає через включений StrictMode. Правильна конфігурація сборки—це коли кожне окруження має свої константи, поведінку та настройки, а не набір #if DEBUG розкидані по коду.
iOS: Xcconfig + Build Configurations
У 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.
Android: Build Types + Product Flavors
На Android конфігурації керуються через build.gradle.kts. Build Types (debug, release, staging) + Product Flavors (free, paid, enterprise) дають матрицю вариантів.
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 доступен у коді після сборки—це генеруємий клас, не захардкодена строка.
Іконки та назви додатків по конфігурації
Staging та Debug сборки повинні візуально відрізнятися від релізних. На iOS це робиться через різні AppIcon asset в Assets.xcassets + умова в xcconfig (ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Staging). На Android—через src/debug/res/ та src/staging/res/ з окремими ic_launcher та strings.xml (з іншим app_name).
React Native та Flutter
У React Native конфігурації по окружениям керуються через react-native-config (.env.staging, .env.production) або через native build types/schemes, описані вище. Пакет react-native-config компілює змінні в нативний код—значення недоступні через process.env під час виконання JS, що безпечніше.
У Flutter—--dart-define або --dart-define-from-file:
flutter build apk --dart-define=API_URL=https://api-staging.myapp.com --flavor staging
Робочий процес
Аудит поточного способу управління конфігураціями → створення xcconfig/buildTypes структури → перенесення захардкоджених значень у конфіги → оновлення CI для сборки потрібного варіанту → настройка іконок та назв → документація для команди.
Срок: 1–3 дні. Стоимость рассчитывается индивидуально.







