Zmienne środowiskowe: co to jest, użycie i konfiguracja w projektach mobilnych

Autor: IT Sectr Opublikowano: 2026-05-31 Czas czytania: 8 min

Zmienne środowiskowe to dynamiczne wartości przekazywane aplikacji na etapie uruchamiania w celu skonfigurowania jej działania bez modyfikacji kodu. Umożliwiają rozdzielenie konfiguracji środowisk programistycznych, testowych i produkcyjnych. Według Twelve-Factor App, 2025, konfiguracja powinna być przechowywana w zmiennych środowiskowych, a nie w kodzie. Zmienne środowiskowe zapewniają bezpieczne zarządzanie kluczami API, adresami URL backendu i flagami funkcjonalności.

Najważniejsze

  • Zmienne środowiskowe oddzielają konfigurację aplikacji od kodu źródłowego dla różnych środowisk uruchomieniowych
  • Pliki .env przechowują zmienne w formacie KEY=VALUE i są wykluczane z repozytorium przez .gitignore
  • iOS używa xcconfig i Build Settings do przekazywania zmiennych na etapie kompilacji
  • Android używa BuildConfig i gradle.properties do generowania pól konfiguracyjnych
  • Bezpieczeństwo: klucze i tokeny powinny być ładowane przez CI/CD, a nie przechowywane w kodzie lub repozytorium

Czym są zmienne środowiskowe

Zmienne środowiskowe to para klucz-wartość, dostępna dla procesu aplikacji przez API systemu operacyjnego. Są przekazywane do procesu podczas jego tworzenia i istnieją tylko przez czas jego działania. W przeciwieństwie do parametrów konfiguracji wbudowanych w kod źródłowy, zmienne środowiskowe nie wymagają ponownej kompilacji, aby zmienić wartości. To fundamentalna zasada Twelve-Factor App, która zapewnia wyraźny podział między kodem a konfiguracją.

W programowaniu mobilnym zmienne środowiskowe rozwiązują problem różnych konfiguracji dla środowisk: programista używa lokalnego serwera, tester — staging, użytkownicy — produkcja. Zamiast przechowywać trzy adresy URL backendu w kodzie z instrukcjami warunkowymi if-else, programista przekazuje jeden URL przez zmienną środowiskową na etapie budowania. Upraszcza to kod i eliminuje ryzyko przypadkowego użycia serwera produkcyjnego w środowisku testowym.

Główną zaletą jest bezpieczeństwo: poufne dane nie trafiają do repozytorium kodu. Klucze API, sekrety Firebase, tokeny dostępu do backendu i certyfikaty są ładowane przez CI/CD bezpośrednio do środowiska budowania. Jeśli osoba nieuprawniona uzyska dostęp do repozytorium kodu, nie znajdzie tam sekretów, ponieważ są one przechowywane w zabezpieczonych magazynach systemu CI i przekazywane tylko na etapie budowania pliku binarnego.

Po co zmienne środowiskowe w programowaniu mobilnym

Projekty mobilne mają co najmniej trzy środowiska: development, staging i produkcja. Każde środowisko wymaga własnego zestawu konfiguracji: adres URL serwera, nazwa pakietu, schemat podpisu i certyfikaty powiadomień push. Bez zmiennych środowiskowych programista musi ręcznie zmieniać konfigurację przed każdym budowaniem, co prowadzi do błędów: zapomniany klucz produkcyjny w kompilacji testowej może spowodować wysyłanie powiadomień do rzeczywistych użytkowników lub zużycie płatnego API.

Rozdział środowisk

Zmienne środowiskowe umożliwiają przełączanie backendu bez zmiany kodu: wystarczy zastąpić wartość w zmiennej API_BASE_URL. Flagi funkcjonalności (feature flags) są zarządzane przez zmienne typu FEATURE_CHAT_ENABLED=true, co pozwala włączać nowe funkcje w staging bez wpływu na produkcję. Dla każdego środowiska tworzony jest własny plik .env, który jest ładowany na etapie budowania.

dart
class AppConfig {
  static final String apiBaseUrl =
    const String.fromEnvironment('API_BASE_URL',
      defaultValue: 'http://localhost:8080');
}

Bezpieczeństwo kluczy

Zakodowane na sztywno klucze to powszechna luka w aplikacjach mobilnych. Osoba nieuprawniona dekompiluje APK lub IPA za pomocą narzędzi takich jak jadx lub Hopper i wyodrębnia sekrety z pliku binarnego. Nawet obfuskacja nie chroni literałów stringów — są łatwe do znalezienia w kodzie po dekompilacji. Zmienne środowiskowe rozwiązują ten problem, przekazując klucze na etapie budowania przez CI/CD, gdzie są maskowane w logach.

kotlin
object Config {
    val apiKey: String =
        System.getenv("API_KEY") ?: throw
            IllegalStateException("API_KEY not set")
}

Integracja CI/CD

Zmienne środowiskowe są integrowane z pipeline'ami budowania: GitHub Actions, GitLab CI, Bitrise i CircleCI obsługują tajne zmienne, które nie są wyświetlane w logach. Na etapie budowania CI podstawia odpowiednie wartości w zależności od gałęzi lub tagu: dla gałęzi develop używane jest staging, dla tagu v* — produkcja. Automatyzuje to proces i eliminuje czynnik ludzki, gwarantując, że każde budowanie otrzymuje poprawny zestaw konfiguracji.

Pliki .env i biblioteki do zarządzania

Plik .env to standardowy sposób przechowywania zmiennych środowiskowych w formacie KEY=VALUE. Nie jest dołączany do repozytorium, zamiast tego do repozytorium dodawany jest .env.example z szablonem wszystkich zmiennych i pustymi wartościami. Każdy programista tworzy własny plik .env z ustawieniami lokalnymi, nie wpływając na konfigurację innych członków zespołu. Dla różnych środowisk używane są osobne pliki: .env.dev, .env.stage, .env.prod.

bash
# .env.example — szablon dla programistów
API_BASE_URL=http://localhost:8080
FEATURE_CHAT_ENABLED=true
SENTRY_DSN=

Dla projektów mobilnych istnieją wyspecjalizowane biblioteki do pracy z plikami .env:

  • flutter_dotenv (Flutter) — ładuje zmienne z .env w runtime przez dotenv.load()
  • BuildConfig (Android) — generuje typowane pola z wartości build.gradle
  • xcconfig (iOS) — podłącza pliki konfiguracyjne do różnych schematów budowania Xcode
  • react-native-config (React Native) — zarządzanie zmiennymi przez pliki .env

Ustawienia gałęzi w CI/CD umożliwiają podstawianie różnych plików .env: .env.dev dla serwerów testowych, .env.stage dla przedpremierowych i .env.prod dla publikacji w sklepach aplikacji. Pliki z sekretami są ładowane z bezpiecznego magazynu (Vault, AWS Secrets Manager) i nie są przechowywane w repozytorium. Gwarantuje to, że nawet przy kompromitacji systemu kontroli wersji sekrety pozostają chronione.

Zmienne środowiskowe w projektach iOS

Ekostystem iOS używa plików xcconfig do zarządzania zmiennymi na poziomie budowania. Są one podłączane do schematów Xcode i umożliwiają nadpisywanie wartości dla konfiguracji Debug i Release. Pliki xcconfig obsługują dziedziczenie: można utworzyć bazowy plik z wspólnymi ustawieniami i specyficzne pliki dla każdego środowiska.

Konfiguracja plików xcconfig

Pliki xcconfig przechowują zmienne w formacie KEY = VALUE i są podłączane do schematu budowania w Xcode przez ustawienia Configuration. Zmienne z xcconfig są dostępne w Info.plist przez składnię $(VARIABLE_NAME), co pozwala używać różnych identyfikatorów pakietu i nazw aplikacji dla różnych schematów. Do szybkiej identyfikacji środowiska do nazwy aplikacji dodawany jest sufiks Dev lub Staging.

bash
# Config/Dev.xcconfig — konfiguracja programistyczna
API_BASE_URL = http://localhost:3000
BUNDLE_ID_SUFFIX = .dev
APP_DISPLAY_NAME = MyApp Dev

Kod Swift do odczytu zmiennych

Do dostępu w runtime do zmiennych w iOS używany jest plik Configuration.swift, który odczytuje wartości z Info.plist przez Bundle.main.object(forInfoDictionaryKey:). To podejście gwarantuje, że zmienne są określane na etapie budowania i dostępne dla aplikacji natychmiast po uruchomieniu. Wartości są odczytywane raz podczas inicjalizacji modułu i cachowane dla szybkiego dostępu przez cały cykl życia aplikacji.

swift
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
    }
}

Zmienne środowiskowe w projektach Android

Android obsługuje zmienne środowiskowe przez BuildConfig — automatycznie generowaną klasę, której pola są określane w pliku build.gradle modułu. BuildConfig jest tworzony na etapie kompilacji dla każdego flavora i typu budowania osobno. Pozwala to mieć różne wartości dla debug i release bez używania instrukcji warunkowych w kodzie, co zwiększa wydajność i bezpieczeństwo.

Konfiguracja pól BuildConfig

Pola BuildConfig są ustawiane przez buildConfigField w defaultConfig lub w konkretnych buildTypes. Dla każdego środowiska tworzony jest osobny buildType lub productFlavor. Zapewnia to ścisłą izolację konfiguracji: debug używa lokalnego serwera, release — produkcji. Pola BuildConfig są statycznie typowane, co eliminuje błędy przy odwołaniach do nich w kodzie.

groovy
// 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 dla wspólnych wartości

Plik gradle.properties w katalogu głównym projektu przechowuje globalne zmienne Gradle. Są one dostępne we wszystkich modułach przez składnię $variableName i używane do określania wersji zależności, flag budowania i kluczy API. W przeciwieństwie do BuildConfig, gradle.properties działa tylko na etapie konfiguracji Gradle, a nie w runtime aplikacji. Dlatego hasła i klucze API określone w gradle.properties nie są widoczne w zdekompilowanym kodzie, ponieważ są używane tylko do generowania BuildConfig na etapie kompilacji.

groovy
# gradle.properties
SENTRY_DSN=https://key@sentry.io/project
MAPS_API_KEY=AIzaSy...

Do bezpiecznego przekazywania sekretów w projektach Android zaleca się używanie local.properties (wykluczonego z VCS) lub ładowanie wartości z zmiennych CI/CD do build.gradle przez System.getenv(). Gwarantuje to, że klucze nie trafią do repozytorium. Podczas publikacji w Google Play Console upewnij się, że wszystkie klucze debugowe zostały zastąpione wersjami produkcyjnymi przez różne buildTypes lub productFlavors z odpowiednimi wartościami BuildConfig.

Często zadawane pytania

Czy można używać zmiennych środowiskowych w Flutter?

Tak, Flutter obsługuje zmienne środowiskowe przez pakiet flutter_dotenv do dostępu w runtime lub przez kanały natywne dla zmiennych platformowych. W Dart dostępny jest również konstruktor String.fromEnvironment do przekazywania wartości na etapie kompilacji przez --dart-define, co jest preferowanym sposobem dla projektów Flutter.

Jaka jest różnica między BuildConfig a gradle.properties?

BuildConfig to klasa Java z typowanymi polami, wygenerowana na etapie kompilacji dla każdego buildType i flavora. gradle.properties to plik tekstowy z parami klucz-wartość, dostępny dla wszystkich modułów Gradle na etapie konfiguracji budowania. BuildConfig działa w runtime aplikacji, gradle.properties — tylko w skryptach Gradle.

Jak zapobiec wyciekowi pliku .env do repozytorium?

Dodaj .env do pliku .gitignore swojego repozytorium. Do repozytorium commituj tylko .env.example z pustymi wartościami i opisem każdej zmiennej. Dla CI/CD używaj zaszyfrowanych sekretów w ustawieniach GitHub Actions, GitLab CI lub Bitrise, które są maskowane w logach i niedostępne do odczytu po zakończeniu budowania.

Jak przekazać zmienne środowiskowe przez CI/CD?

Większość systemów CI obsługuje tajne zmienne środowiskowe. W GitHub Actions są to Secrets, w GitLab CI — CI/CD Variables, w Bitrise — Secrets. Na etapie budowania są przekazywane do skryptu budowania przez process.env lub System.getenv(). Tajne zmienne nie są wyświetlane w logach budowania i są niedostępne w forka repozytorium.

Czym są feature flags przez zmienne środowiskowe?

Feature flags to zmienne boolowskie sterujące włączaniem lub wyłączaniem funkcjonalności bez ponownej kompilacji kodu. Przykład: FEATURE_NEW_PAYMENT=true włącza nowy system płatności w staging do testowania. W produkcji ta sama flaga jest ustawiona na false do pełnego wdrożenia backendu. Pozwala to bezpiecznie wdrażać zmiany etapami i wycofywać je w przypadku problemów.

Podsumowanie

  • Zmienne środowiskowe oddzielają konfigurację od kodu źródłowego dla różnych środowisk programistycznych
  • Pliki .env z szablonem .env.example to standard zarządzania zmiennymi w zespołach z rozgraniczeniem środowisk
  • iOS xcconfig podłącza pliki konfiguracyjne do schematów Xcode z obsługą dziedziczenia i integracji Info.plist
  • Android BuildConfig generuje typowane pola z build.gradle dla każdego buildType osobno
  • Sekrety CI/CD przekazują poufne dane na etapie budowania bez przechowywania ich w repozytorium
  • Feature flags przez zmienne umożliwiają włączanie funkcjonalności w konkretnym środowisku bez ponownej kompilacji
  • Bezpieczeństwo: klucze są szyfrowane w CI i nie trafiają do dekompilowalnego pliku binarnego aplikacji

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również