Променљиве окружења су динамичке вредности које се прослеђују апликацији при покретању ради подешавања понашања без измене кода. Оне омогућавају раздвајање конфигурација развоја, тестирања и продукције. Према Twelve-Factor App, 2025, конфигурација треба да се чува у променљивама окружења, а не у коду. Променљиве окружења обезбеђују безбедно управљање АПИ кључевима, УРЛ бекенда и заставицама функционалности.
Главно
Променљиве окружења су пар кључ-вредност, доступан процесу апликације кроз API оперативног система. Оне се прослеђују процесу при његовом креирању и постоје само током његовог рада. За разлику од параметара конфигурације уграђених у изворни код, променљиве окружења не захтевају поновну компилацију за промену вредности. Ово је фундаментални принцип Twelve-Factor App, који обезбеђује јасно раздвајање између кода и конфигурације.
У мобилном развоју, променљиве окружења решавају проблем различитих конфигурација за окружења: програмер користи локални сервер, тестер — staging, корисници — продукцију. Уместо чувања три УРЛ бекенда у коду са условним операторима if-else, програмер прослеђује један УРЛ кроз променљиву окружења у фази изградње. Ово поједностављује код и елиминише ризик случајне употребе продукционог сервера у тестном окружењу.
Главна предност је безбедност: осетљиви подаци не доспевају у репозиторијум кода. АПИ кључеви, Firebase тајне, токени приступа бекенду и сертификати учитавају се кроз CI/CD директно у окружење изградње. Ако нападач добије приступ репозиторијуму кода, неће наћи тајне тамо, јер се one чувају у заштићеним складиштима CI система и прослеђују се само у фази изградње бинарне датотеке.
Мобилни пројекти имају најмање три окружења: development, staging и продукцију. Свако окружење захтева свој скуп конфигурација: УРЛ сервера, назив пакета, шему потписивања и сертификате 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');
}
Чврсто кодирани кључеви су честа рањивост мобилних апликација. Нападач декомпилира АПК или ИПА помоћу алата попут jadx или Hopper и извлачи тајне из бинарне датотеке. Чак ни обфускација не штити стринг литерале — они се лако проналазе у коду након декомпилације. Променљиве окружења решавају овај проблем, прослеђујући кључеве у фази изградње кроз CI/CD, где су маскирани у логовима.
object Config {
val apiKey: String =
System.getenv("API_KEY") ?: throw
IllegalStateException("API_KEY not set")
}
Променљиве окружења се интегришу са pipeline-овима изградње: GitHub Actions, GitLab CI, Bitrise и CircleCI подржавају тајне променљиве које се не приказују у логовима. У фази изградње, CI замењује одговарајуће вредности у зависности од гране или ознаке: за грану develop користи се staging, за ознаку v* — продукција. Ово аутоматизује процес и елиминише људски фактор, гарантујући да свака изградња добија прави скуп конфигурације.
Датотека .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 се креира у фази компилације за сваки flavor и тип изградње посебно. Ово омогућава различите вредности за 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 и користе се за навођење верзија зависности, заставица изградње и АПИ кључева. За разлику од BuildConfig-а, gradle.properties ради само у фази конфигурације Gradle-а, а не у runtime апликације. Стога лозинке и АПИ кључеви наведени у 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, уверите се да су сви debug кључеви замењени продукционим верзијама кроз различите buildTypes или productFlavors са одговарајућим BuildConfig вредностима.
Често постављана питања
Да, Flutter подржава променљиве окружења кроз пакет flutter_dotenv за runtime приступ или кроз native канале за платформске променљиве. У 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. У фази изградње, one се прослеђују build скрипти кроз process.env или System.getenv(). Тајне променљиве се не приказују у логовима изградње и нису доступне у форковима репозиторијума.
Feature flags су булове променљиве које контролишу укључивање или искључивање функционалности без поновне компилације кода. Пример: FEATURE_NEW_PAYMENT=true укључује нови систем плаћања у staging-у за тестирање. У продукцији иста заставица је постављена на false до потпуног постављања бекенда. Ово омогућава безбедно увођење промена у фазама и повлачење у случају проблема.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође