Змінні середовища — динамічні значення, які передаються додатку на етапі запуску для налаштування поведінки без зміни коду. Вони дозволяють розділяти конфігурації розробки, тестування та продакшну. За даними Twelve-Factor App, 2025, конфігурація повинна зберігатися в змінних середовища, а не в коді. Змінні середовища забезпечують безпечне управління API-ключами, URL бекенду та прапорцями функціональності.
Головне
Змінні середовища — це пара ключ-значення, доступна процесу додатка через API операційної системи. Вони передаються процесу при його створенні та існують тільки під час його роботи. На відміну від параметрів конфігурації, вбудованих у вихідний код, змінні середовища не вимагають перекомпіляції для зміни значень. Це фундаментальний принцип Twelve-Factor App, який забезпечує чітке розділення між кодом і конфігурацією.
У мобільній розробці змінні середовища вирішують проблему різних конфігурацій для середовищ: розробник використовує локальний сервер, тестувальник — staging, користувачі — production. Замість того щоб зберігати три URL бекенду в коді з умовними операторами if-else, розробник передає один URL через змінну середовища на етапі збірки. Це спрощує код і виключає ризик випадкового використання продакшн-сервера в тестовому середовищі.
Основна перевага — безпека: чутливі дані не потрапляють до репозиторію коду. API-ключі, секрети Firebase, токени доступу до бекенду та сертифікати завантажуються через CI/CD безпосередньо в середовище збірки. Якщо зловмисник отримає доступ до репозиторію коду, він не знайде там секретів, оскільки вони зберігаються в захищених сховищах CI-системи та передаються тільки на етапі збірки бінарного файлу.
Мобільні проекти мають мінімум три середовища: development, staging та production. Кожне середовище вимагає свого набору конфігурацій: URL сервера, ім'я пакета, схема підпису та сертифікати push-сповіщень. Без змінних середовища розробнику доводиться вручну змінювати конфігурацію перед кожною збіркою, що призводить до помилок: забутий продакшн-ключ у тестовій збірці може викликати відправку сповіщень реальним користувачам або витрату платного API.
Змінні середовища дозволяють перемикати бекенд без зміни коду: достатньо замінити значення в змінній API_BASE_URL. Прапорці функціональності (feature flags) керуються через змінні типу FEATURE_CHAT_ENABLED=true, що дозволяє включати нові можливості в staging без впливу на продакшн. Для кожного середовища створюється свій .env файл, який завантажується на етапі збірки.
class AppConfig {
static final String apiBaseUrl =
const String.fromEnvironment('API_BASE_URL',
defaultValue: 'http://localhost:8080');
}
Жорстко закодовані ключі — поширена вразливість мобільних додатків. Зловмисник декомпілює APK або IPA за допомогою інструментів типу jadx або Hopper та витягує секрети з бінарного файлу. Навіть обфускація не захищає строкові літерали — вони легко знаходяться в коді після декомпіляції. Змінні середовища вирішують цю проблему, передаючи ключі на етапі збірки через CI/CD, де вони маскуються в логах.
object Config {
val apiKey: String =
System.getenv("API_KEY") ?: throw
IllegalStateException("API_KEY not set")
}
Змінні середовища інтегруються з пайплайнами збірки: GitHub Actions, GitLab CI, Bitrise та CircleCI підтримують секретні змінні, які не відображаються в логах. На етапі збірки CI підставляє потрібні значення залежно від гілки або тега: для гілки develop використовується staging, для тега v* — production. Це автоматизує процес та виключає людський фактор, гарантуючи, що кожна збірка отримує правильний набір конфігурації.
Файл .env — стандартний спосіб зберігання змінних середовища у форматі KEY=VALUE. Він не включається в репозиторій, а натомість до репозиторію додається .env.example з шаблоном усіх змінних і порожніми значеннями. Кожен розробник створює свій .env файл з локальними налаштуваннями, не зачіпаючи конфігурацію інших членів команди. Для різних середовищ використовуються окремі файли: .env.dev, .env.stage, .env.prod.
# .env.example — шаблон для розробників
API_BASE_URL=http://localhost:8080
FEATURE_CHAT_ENABLED=true
SENTRY_DSN=
Для мобільних проектів існують спеціалізовані бібліотеки для роботи з .env файлами:
Налаштування гілкування в CI/CD дозволяють підставляти різні .env файли: .env.dev для тестових серверів, .env.stage для передрелізу та .env.prod для публікації в магазини додатків. Файли з секретами завантажуються із безпечного сховища (Vault, AWS Secrets Manager) і не зберігаються в репозиторії. Це гарантує, що навіть при компрометації системи контролю версій секрети залишаються захищеними.
iOS екосистема використовує xcconfig файли для управління змінними на рівні збірки. Вони підключаються до схем Xcode та дозволяють перевизначати значення для Debug та Release конфігурацій. xcconfig файли підтримують успадкування: можна створити базовий файл зі спільними налаштуваннями та специфічні файли для кожного середовища.
Файли xcconfig зберігають змінні у форматі KEY = VALUE та підключаються до схеми збірки в Xcode через налаштування Configuration. Змінні з xcconfig доступні в Info.plist через синтаксис $(VARIABLE_NAME), що дозволяє використовувати різні ідентифікатори бандла та назви додатка для різних схем. Для швидкої ідентифікації середовища до назви додатка додається суфікс Dev або Staging.
# Config/Dev.xcconfig — конфігурація розробки
API_BASE_URL = http://localhost:3000
BUNDLE_ID_SUFFIX = .dev
APP_DISPLAY_NAME = MyApp Dev
Для runtime-доступу до змінних в iOS використовується файл Configuration.swift, який читає значення з Info.plist через Bundle.main.object(forInfoDictionaryKey:). Цей підхід гарантує, що змінні визначаються на етапі збірки та доступні додатку одразу після запуску. Значення читаються один раз при ініціалізації модуля та кешуються для швидкого доступу протягом життєвого циклу додатка.
enum AppEnvironment {
static var apiBaseURL: URL {
guard let urlString = Bundle.main
.object(forInfoDictionaryKey: "API_BASE_URL"),
let url = URL(string: urlString as! String)
else { fatalError("API_BASE_URL is not configured") }
return url
}
static var isChatEnabled: Bool {
Bundle.main.object(
forInfoDictionaryKey: "FEATURE_CHAT_ENABLED"
) as? Bool ?? false
}
}
Android підтримує змінні середовища через BuildConfig — автоматично генерований клас, поля якого визначаються в build.gradle файлі модуля. BuildConfig створюється на етапі компіляції для кожного флейвору та типу збірки окремо. Це дозволяє мати різні значення для debug та release без використання умовних операторів у коді, що підвищує продуктивність та безпеку.
Поля BuildConfig задаються через buildConfigField в defaultConfig або в конкретних buildTypes. Для кожного середовища створюється окремий buildType або productFlavor. Це забезпечує строгу ізоляцію конфігурацій: debug використовує локальний сервер, release — продакшн. Поля BuildConfig статично типізовані, що виключає помилки при зверненні до них у коді.
// build.gradle (Module: app)
android {
defaultConfig {
buildConfigField "String", "API_BASE_URL",
"\"http://localhost:8080\""
}
buildTypes {
debug {
buildConfigField "String", "API_BASE_URL",
"\"http://dev.api.itsectr.com\""
}
release {
buildConfigField "String", "API_BASE_URL",
"\"https://api.itsectr.com\""
}
}
}
Файл gradle.properties в корені проекту зберігає глобальні змінні Gradle. Вони доступні у всіх модулях через синтаксис $variableName та використовуються для вказівки версій залежностей, прапорців збірки та ключів API. На відміну від BuildConfig, gradle.properties працює тільки на етапі конфігурації Gradle, а не в runtime додатка. Тому паролі та ключі API, вказані в gradle.properties, не видно в декомпільованому коді, оскільки вони використовуються тільки для генерації BuildConfig на етапі компіляції.
# gradle.properties
SENTRY_DSN=https://key@sentry.io/project
MAPS_API_KEY=AIzaSy...
Для безпечної передачі секретів в Android проектах рекомендується використовувати local.properties (виключений з VCS) або завантажувати значення з CI/CD змінних в build.gradle через System.getenv(). Це гарантує, що ключі не потраплять до репозиторію. При публікації в Google Play Console переконайтеся, що всі відлагоджувальні ключі замінені на продакшн-версії через різні buildTypes або productFlavors з відповідними значеннями BuildConfig.
Часті запитання
Так, Flutter підтримує змінні середовища через пакет flutter_dotenv для runtime-доступу або через нативні канали для платформених змінних. У Dart також доступний конструктор String.fromEnvironment для передачі значень на етапі компіляції через --dart-define, що є кращим способом для Flutter проектів.
BuildConfig — це Java-клас із типізованими полями, згенерований на етапі компіляції для кожного buildType та flavor. gradle.properties — текстовий файл із парами ключ-значення, доступний усім модулям Gradle на етапі конфігурації збірки. BuildConfig працює в runtime додатка, gradle.properties — тільки в скриптах Gradle.
Додайте .env до файлу .gitignore вашого репозиторію. До репозиторію комітьте тільки .env.example з порожніми значеннями та описом кожної змінної. Для CI/CD використовуйте зашифровані секрети в налаштуваннях GitHub Actions, GitLab CI або Bitrise, які маскуються в логах та недоступні для читання після завершення збірки.
Більшість CI-систем підтримують секретні змінні середовища. В GitHub Actions це Secrets, в GitLab CI — CI/CD Variables, в Bitrise — Secrets. На етапі збірки вони передаються в білд-скрипт через process.env або System.getenv(). Секретні змінні не відображаються в логах збірки та недоступні в форках репозиторію.
Feature flags — це булеві змінні, які керують включенням або вимкненням функціональності без перекомпіляції коду. Приклад: FEATURE_NEW_PAYMENT=true включає нову платіжну систему в staging для тестування. В production той самий прапорець встановлений в false до повного розгортання бекенду. Це дозволяє безпечно впроваджувати зміни поетапно та відкочувати їх при проблемах.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також