Le variabili d'ambiente sono valori dinamici passati a un'applicazione all'avvio per configurarne il comportamento senza modificare il codice. Consentono di separare le configurazioni di sviluppo, test e produzione. Secondo Twelve-Factor App, 2025, la configurazione dovrebbe essere memorizzata nelle variabili d'ambiente, non nel codice. Le variabili d'ambiente garantiscono una gestione sicura delle chiavi API, dell'URL del backend e dei flag di funzionalità.
Punti Chiave
Le variabili d'ambiente sono coppie chiave-valore accessibili al processo dell'applicazione tramite l'API del sistema operativo. Vengono passate al processo quando viene creato ed esistono solo durante la sua esecuzione. A differenza dei parametri di configurazione incorporati nel codice sorgente, le variabili d'ambiente non richiedono ricompilazione per modificare i valori. Questo è un principio fondamentale di Twelve-Factor App, che garantisce una chiara separazione tra codice e configurazione.
Nello sviluppo mobile, le variabili d'ambiente risolvono il problema delle diverse configurazioni per gli ambienti: lo sviluppatore utilizza un server locale, il tester utilizza staging e gli utenti utilizzano la produzione. Invece di memorizzare tre URL backend nel codice con istruzioni condizionali if-else, lo sviluppatore passa un URL attraverso una variabile d'ambiente in fase di compilazione. Questo semplifica il codice ed elimina il rischio di utilizzare accidentalmente il server di produzione in un ambiente di test.
Il vantaggio principale è la sicurezza: i dati sensibili non finiscono nel repository del codice. Le chiavi API, i segreti Firebase, i token di accesso al backend e i certificati vengono caricati tramite CI/CD direttamente nell'ambiente di compilazione. Se un utente malintenzionato ottiene accesso al repository del codice, non troverà segreti lì, poiché sono memorizzati in archivi protetti del sistema CI e vengono passati solo in fase di compilazione del file binario.
I progetti mobile hanno almeno tre ambienti: sviluppo, staging e produzione. Ogni ambiente richiede il proprio insieme di configurazioni: URL del server, nome del pacchetto, schema di firma e certificati di notifiche push. Senza variabili d'ambiente, lo sviluppatore deve modificare manualmente la configurazione prima di ogni compilazione, causando errori: una chiave di produzione dimenticata in una compilazione di test può inviare notifiche a utenti reali o consumare API a pagamento.
Le variabili d'ambiente consentono di cambiare backend senza modificare il codice: basta cambiare il valore nella variabile API_BASE_URL. I flag di funzionalità sono gestiti tramite variabili come FEATURE_CHAT_ENABLED=true, consentendo di attivare nuove funzionalità in staging senza influenzare la produzione. Ogni ambiente ha il proprio file .env che viene caricato in fase di compilazione.
class AppConfig {
static final String apiBaseUrl =
const String.fromEnvironment('API_BASE_URL',
defaultValue: 'http://localhost:8080');
}
Le chiavi hardcodate sono una vulnerabilità comune nelle applicazioni mobile. Un utente malintenzionato decompila APK o IPA utilizzando strumenti come jadx o Hopper ed estrae segreti dal file binario. Anche l'offuscamento non protegge i letterali di stringa — si trovano facilmente nel codice dopo la decompilazione. Le variabili d'ambiente risolvono questo problema passando le chiavi in fase di compilazione tramite CI/CD, dove vengono mascherate nei log.
object Config {
val apiKey: String =
System.getenv("API_KEY") ?: throw
IllegalStateException("API_KEY not set")
}
Le variabili d'ambiente si integrano con le pipeline di compilazione: GitHub Actions, GitLab CI, Bitrise e CircleCI supportano variabili segrete che non vengono visualizzate nei log. In fase di compilazione, il CI sostituisce i valori appropriati in base al branch o al tag: per il branch develop viene utilizzato staging, per il tag v* viene utilizzata la produzione. Questo automatizza il processo ed elimina il fattore umano, garantendo che ogni compilazione riceva il set di configurazione corretto.
Il file .env è un modo standard per memorizzare le variabili d'ambiente nel formato KEY=VALUE. Non viene incluso nel repository; invece, viene aggiunto .env.example con un modello di tutte le variabili e valori vuoti. Ogni sviluppatore crea il proprio file .env con impostazioni locali senza influenzare le configurazioni degli altri membri del team. File separati vengono utilizzati per ambienti diversi: .env.dev, .env.stage, .env.prod.
# .env.example — modello per sviluppatori
API_BASE_URL=http://localhost:8080
FEATURE_CHAT_ENABLED=true
SENTRY_DSN=
Per i progetti mobile, esistono librerie specializzate per lavorare con i file .env:
Le impostazioni di branching in CI/CD consentono di sostituire diversi file .env: .env.dev per i server di test, .env.stage per il pre-rilascio e .env.prod per la pubblicazione negli store di applicazioni. I file con segreti vengono caricati da un archivio sicuro (Vault, AWS Secrets Manager) e non vengono memorizzati nel repository. Questo garantisce che anche se il sistema di controllo versione viene compromesso, i segreti rimangono protetti.
L'ecosistema iOS utilizza file xcconfig per gestire le variabili a livello di compilazione. Vengono allegati agli schemi Xcode e consentono di sovrascrivere i valori per le configurazioni Debug e Release. I file xcconfig supportano l'ereditarietà: è possibile creare un file di base con impostazioni comuni e file specifici per ogni ambiente.
I file xcconfig memorizzano le variabili nel formato KEY = VALUE e vengono allegati a uno schema di compilazione in Xcode tramite le impostazioni di Configuration. Le variabili da xcconfig sono disponibili in Info.plist tramite la sintassi $(NOME_VARIABILE), consentendo identificatori di bundle e nomi di applicazione diversi per schemi diversi. Per una rapida identificazione dell'ambiente, il suffisso Dev o Staging viene aggiunto al nome dell'applicazione.
# Config/Dev.xcconfig — configurazione di sviluppo
API_BASE_URL = http://localhost:3000
BUNDLE_ID_SUFFIX = .dev
APP_DISPLAY_NAME = MyApp Dev
Per l'accesso in fase di esecuzione alle variabili in iOS, viene utilizzato il file Configuration.swift, che legge i valori da Info.plist tramite Bundle.main.object(forInfoDictionaryKey:). Questo approccio garantisce che le variabili siano definite in fase di compilazione e siano disponibili per l'applicazione immediatamente dopo l'avvio. I valori vengono letti una volta durante l'inizializzazione del modulo e memorizzati nella cache per un accesso rapido durante l'intero ciclo di vita dell'applicazione.
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 supporta le variabili d'ambiente tramite BuildConfig — una classe generata automaticamente i cui campi sono definiti nel file build.gradle del modulo. BuildConfig viene creato in fase di compilazione per ogni flavor e tipo di compilazione separatamente. Ciò consente di avere valori diversi per debug e release senza utilizzare operatori condizionali nel codice, migliorando le prestazioni e la sicurezza.
I campi di BuildConfig vengono impostati tramite buildConfigField in defaultConfig o in buildTypes specifici. Un buildType o productFlavor separato viene creato per ogni ambiente. Ciò garantisce un rigoroso isolamento della configurazione: debug utilizza un server locale, release utilizza la produzione. I campi BuildConfig sono staticamente tipizzati, eliminando errori durante l'accesso nel codice.
// 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\""
}
}
}
Il file gradle.properties nella radice del progetto memorizza le variabili globali di Gradle. Sono disponibili in tutti i moduli tramite la sintassi $variableName e vengono utilizzati per specificare versioni delle dipendenze, flag di compilazione e chiavi API. A differenza di BuildConfig, gradle.properties funziona solo in fase di configurazione di Gradle, non in fase di esecuzione dell'applicazione. Pertanto, le password e le chiavi API specificate in gradle.properties non sono visibili nel codice decompilato, poiché vengono utilizzate solo per generare BuildConfig in fase di compilazione.
# gradle.properties
SENTRY_DSN=https://key@sentry.io/project
MAPS_API_KEY=AIzaSy...
Per il trasferimento sicuro dei segreti nei progetti Android, si consiglia di utilizzare local.properties (escluso dal VCS) o caricare i valori dalle variabili CI/CD in build.gradle tramite System.getenv(). Questo garantisce che le chiavi non finiscano nel repository. Quando si pubblica su Google Play Console, assicurarsi che tutte le chiavi di debug siano sostituite con versioni di produzione attraverso diversi buildTypes o productFlavors con i corrispondenti valori BuildConfig.
Domande Frequenti
Sì, Flutter supporta le variabili d'ambiente attraverso il pacchetto flutter_dotenv per l'accesso in fase di esecuzione o attraverso canali nativi per le variabili di piattaforma. Dart dispone anche del costruttore String.fromEnvironment per passare valori in fase di compilazione tramite --dart-define, che è il metodo preferito per i progetti Flutter.
BuildConfig è una classe Java con campi tipizzati generata in fase di compilazione per ogni buildType e flavor. gradle.properties è un file di testo con coppie chiave-valore accessibile a tutti i moduli Gradle in fase di configurazione della compilazione. BuildConfig funziona in fase di esecuzione dell'applicazione, gradle.properties — solo negli script Gradle.
Aggiungi .env al file .gitignore del tuo repository. Nel repository, includi solo .env.example con valori vuoti e una descrizione di ogni variabile. Per CI/CD, utilizza segreti crittografati nelle impostazioni di GitHub Actions, GitLab CI o Bitrise, che vengono mascherati nei log e non sono disponibili per la lettura dopo il completamento della compilazione.
La maggior parte dei sistemi CI supporta variabili d'ambiente segrete. In GitHub Actions sono Secrets, in GitLab CI — CI/CD Variables, in Bitrise — Secrets. In fase di compilazione, vengono passate allo script di compilazione tramite process.env o System.getenv(). Le variabili segrete non vengono visualizzate nei log di compilazione e non sono disponibili nei fork del repository.
I flag di funzionalità sono variabili booleane che controllano l'attivazione o la disattivazione di funzionalità senza ricompilare il codice. Esempio: FEATURE_NEW_PAYMENT=true attiva un nuovo sistema di pagamento in staging per i test. In produzione, lo stesso flag è impostato su false fino a quando il backend non è completamente distribuito. Ciò consente di implementare le modifiche in modo incrementale e sicuro e di annullarle in caso di problemi.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche