.xcconfig è un file di configurazione di Xcode in formato “chiave=valore” che gestisce centralmente le Build Settings di un progetto. Invece di modificare manualmente i parametri nell'interfaccia di Xcode per ogni configurazione, gli sviluppatori li descrivono in un file di testo che può essere versionato e riutilizzato tra progetti. Secondo Apple Developer Documentation, 2025, l'uso di .xcconfig riduce il tempo di configurazione del progetto del 70% ed elimina le discrepanze di configurazione tra sviluppatori. I file .xcconfig possono ereditare l'uno dall'altro, formando una catena di configurazioni.
Punti chiave
.xcconfig (file di configurazione Xcode) è un file di testo semplice che contiene le Build Settings nel formato PARAMETER_NAME = value. I file .xcconfig vengono utilizzati per la gestione centralizzata delle configurazioni di compilazione di Xcode: sostituiscono la modifica manuale dei campi nell'interfaccia Build Settings. Ogni .xcconfig è collegato a una Build Configuration (Debug, Release) o all'intero progetto e può sovrascrivere qualsiasi build setting: SWIFT_VERSION, IPHONEOS_DEPLOYMENT_TARGET, PRODUCT_BUNDLE_IDENTIFIER, CODE_SIGN_STYLE, PROVISIONING_PROFILE_SPECIFIER.
Prima dell'avvento di .xcconfig, le impostazioni di compilazione erano memorizzate solo in project.pbxproj — un file binario/plist difficile da leggere nei diff e impossibile da commentare. .xcconfig ha risolto questo problema: gli sviluppatori possono commentare i parametri, raggrupparli per significato, creare file versionabili per diversi ambienti ed ereditare parametri tra file. Ciò ha reso .xcconfig lo standard de facto per la gestione della configurazione nei progetti iOS.
I file .xcconfig si trovano all'interno del progetto, di solito nella cartella Configurations/ o BuildConfig/. Ogni file corrisponde a una Build Configuration: Debug.xcconfig, Release.xcconfig, Staging.xcconfig. Inoltre, viene creato un file Shared.xcconfig comune, incluso in tutte le configurazioni tramite #include. Ciò consente di definire i parametri comuni una volta e sovrascrivere quelli specifici nei file di configurazione.
Leggibilità dei diff: le modifiche in .xcconfig sono visibili in Git diff come righe normali. A differenza di project.pbxproj, dove la modifica dell'ordine dei campi mostra 50 righe di modifiche per una singola modifica di parametro. Commenti: in .xcconfig è possibile spiegare perché ogni parametro è necessario. Ereditarietà: è possibile creare una configurazione di base con impostazioni comuni e sovrascrivere solo i parametri necessari per Debug e Release.
La sintassi di .xcconfig è il più semplice possibile: ogni riga è un parametro, nome e valore separati da un segno di uguale. Gli spazi intorno a = vengono ignorati. I valori possono contenere variabili nei formati $(VARIABLE_NAME) o ${VARIABLE_NAME}. I commenti iniziano con // o # e si applicano fino alla fine della riga. Le righe continuano sulla riga successiva utilizzando una barra rovesciata \. Le righe vuote vengono ignorate.
Le variabili in .xcconfig possono fare riferimento ad altre variabili, creando valori compositi. Ad esempio: PRODUCT_NAME = MyApp, PRODUCT_BUNDLE_IDENTIFIER = com.example.$(PRODUCT_NAME). Xcode valuta il valore al momento della compilazione, sostituendo i valori effettivi delle variabili. AGP supporta anche variabili di sistema: ARCHS, SDK_NAME, CONFIGURATION, PLATFORM_NAME, impostate dall'ambiente di compilazione.
Per la configurazione condizionale, vengono utilizzate direttive di piattaforma tra parentesi quadre: PARAMETER[sdk=iphoneos*] = value. Ad esempio, SUPPORTED_PLATFORMS[sdk=iphoneos*] = iphoneos imposta il parametro solo per le build iOS. I caratteri jolly sono supportati: * (qualsiasi carattere), ? (un carattere). Le direttive condizionali consentono di avere un singolo .xcconfig per più piattaforme e impostare valori diversi per iOS e macOS in un unico file.
// Shared.xcconfig — impostazioni comuni del progetto
SWIFT_VERSION = 5.0
IPHONEOS_DEPLOYMENT_TARGET = 16.0
SDKROOT = iphoneos
TARGETED_DEVICE_FAMILY = 1,2
// Identificatore bundle — composto da prefisso e nome
BUNDLE_ID_PREFIX = com.example
PRODUCT_NAME = MyApp
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME)
// Impostazione condizionale per macOS
SUPPORTED_PLATFORMS[sdk=macosx*] = macosx
PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*] = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).mac
// Versionamento
MARKETING_VERSION = 2.4.1
CURRENT_PROJECT_VERSION = 37
#include è una direttiva del preprocessore .xcconfig che include il contenuto di un altro file .xcconfig. Le direttive possono essere annidate: Shared.xcconfig può #include “Base.xcconfig”, Debug.xcconfig può #include “Shared.xcconfig”. La catena di ereditarietà consente di costruire una gerarchia di configurazioni, dove ogni livello sovrascrive i parametri del precedente. #include funziona secondo il principio dell'ultima scrittura: se lo stesso parametro è definito sia nel file incluso che in quello principale, il valore del file principale ha priorità.
La gerarchia corretta per un tipico progetto iOS: Base.xcconfig (parametri più comuni) → Shared.xcconfig (impostazioni del progetto) → Debug.xcconfig o Release.xcconfig. Base.xcconfig definisce gli standard (SWIFT_VERSION, DEPLOYMENT_TARGET), Shared.xcconfig — le specificità del progetto (PRODUCT_NAME, PREPROCESSOR_DEFINITIONS), Debug/Release — l'ambiente (DEBUG_INFORMATION_FORMAT, OPTIMIZATION_CFLAGS). #include non consente cicli — Xcode genererà un errore se viene rilevata una dipendenza circolare.
Esempio: Config/Base.xcconfig → Config/iOS/Shared.xcconfig → Config/iOS/Debug.xcconfig. Questa struttura consente di riutilizzare Base per progetti iOS, macOS e tvOS, e Shared solo per iOS. Nota: #include utilizza un nome file o un percorso relativo dalla posizione del .xcconfig radice. I percorsi assoluti non sono consigliati — rompono la compilazione su altre macchine e in CI/CD.
// --- Config/Base.xcconfig ---
SWIFT_VERSION = 5.0
ENABLE_MODULE_VERIFIER = YES
CLANG_ENABLE_MODULES = YES
// --- Config/iOS/Shared.xcconfig ---
#include "../Base.xcconfig"
IPHONEOS_DEPLOYMENT_TARGET = 16.0
PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp
// --- Config/iOS/Debug.xcconfig ---
#include "Shared.xcconfig"
OPTIMIZATION_CFLAGS = -O0
DEBUG_INFORMATION_FORMAT = dwarf
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG
ENABLE_TESTABILITY = YES
// --- Config/iOS/Release.xcconfig ---
#include "Shared.xcconfig"
OPTIMIZATION_CFLAGS = -Osize
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
SWIFT_COMPILATION_MODE = wholemodule
Il collegamento di .xcconfig a un progetto viene effettuato in Project Info → Configurations. Per ogni Build Configuration (Debug, Release, AdHoc), il .xcconfig corrispondente viene selezionato dal menu a discesa “Based on Configuration File”. Se una configurazione non è collegata a un file, Xcode utilizza i valori da project.pbxproj. Dopo aver selezionato .xcconfig, tutti i parametri del file diventano attivi per quella configurazione.
È importante distinguere tra configurazioni a livello di progetto e a livello di target. Un .xcconfig a livello di progetto imposta i parametri predefiniti per tutti i target. Un .xcconfig a livello di target li sovrascrive per un target specifico. Se un parametro non è impostato nel .xcconfig a livello di target, viene utilizzato il valore dal livello di progetto. Se non è impostato nemmeno lì, viene utilizzato il valore da project.pbxproj. Regola pratica: inserisci i parametri comuni (compilazione, versioni) a livello di progetto e le specificità del target (identificatore bundle, provisioning) a livello di target.
In caso di conflitto tra .xcconfig e i Build Settings dell'interfaccia, il valore dall'interfaccia ha priorità (sovrascrive .xcconfig). Ciò può creare confusione: uno sviluppatore modifica un Build Setting nell'interfaccia senza sapere che .xcconfig specifica un valore diverso. Si consiglia di passare completamente a .xcconfig e di non toccare i Build Settings dell'interfaccia. Per verificare quale parametro viene applicato, usa xcrun xcodebuild -showBuildSettings — il comando mostrerà i valori finali di tutti i parametri dopo aver risolto tutti i livelli.
Considera una configurazione a tre livelli: Dev (sviluppo locale), Staging (server di test), Production (rilascio). Per ogni ambiente viene creato un .xcconfig separato, che definisce valori diversi di API_URL, logging e certificati. Dev usa localhost, Staging usa staging.api.example.com, Production usa api.example.com. Tutti e tre ereditano il Shared.xcconfig comune tramite #include.
Il parametro chiave che differisce tra gli ambienti è PRODUCT_BUNDLE_IDENTIFIER. Per Dev: com.example.myapp.dev, per Staging: com.example.myapp.staging, per Production: com.example.myapp. ID bundle diversi consentono di installare tutte e tre le versioni su un singolo dispositivo contemporaneamente. Differiscono anche CODE_SIGN_IDENTITY (Apple Development per Dev, Apple Distribution per Production) e PROVISIONING_PROFILE_SPECIFIER.
Per passare valori al codice, si utilizzano INFOPLIST_PREFIX_HEADER o OTHER_SWIFT_FLAGS con preprocessore -D. Swift non ha un preprocessore, quindi vengono utilizzate Active Compilation Conditions: SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEV. Nel codice: #if DEV; #elseif STAGING; #else; #endif. Per Objective-C si usa GCC_PREPROCESSOR_DEFINITIONS. Ciò consente di compilare codice diverso per ambienti diversi senza modificare i file sorgente.
// --- Config/Dev.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).dev
CODE_SIGN_IDENTITY = Apple Development
PROVISIONING_PROFILE_SPECIFIER = Dev Profile
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG DEV
OTHER_SWIFT_FLAGS = -D DEV
// URL API tramite Info.plist — il valore viene sostituito
API_BASE_URL = http://localhost:3000/api
// --- Config/Staging.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).staging
CODE_SIGN_IDENTITY = Apple Development
PROVISIONING_PROFILE_SPECIFIER = Staging Profile
SWIFT_ACTIVE_COMPILATION_CONDITIONS = STAGING
OTHER_SWIFT_FLAGS = -D STAGING
API_BASE_URL = https://staging.api.example.com/v2
// --- Config/Production.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME)
CODE_SIGN_IDENTITY = Apple Distribution
PROVISIONING_PROFILE_SPECIFIER = AppStore Distribution
SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE
API_BASE_URL = https://api.example.com/v3
I valori da .xcconfig possono essere passati a Info.plist tramite variabili $(PARAMETER_NAME). Se un parametro è definito in .xcconfig (ad esempio, API_BASE_URL), può essere utilizzato in Info.plist: <key>ApiBaseUrl</key><string>$(API_BASE_URL)</string>. Al momento della compilazione, Xcode sostituisce $(API_BASE_URL) con il valore da .xcconfig. Ciò consente di configurare l'applicazione senza modificare il codice — basta cambiare lo schema.
I parametri .xcconfig utilizzati in Info.plist devono essere pubblici — finiscono nel binario e sono visibili nell'applicazione decompilata. Non utilizzare .xcconfig per valori segreti (token, password) — utilizza servizi come Firebase Remote Config, eseguiti sul server. .xcconfig per Info.plist è adatto per: URL dei server, nomi di entità, identificatori di tracker, feature flags.
Accesso ai valori di Info.plist nel codice: Bundle.main.object(forInfoDictionaryKey: “ApiBaseUrl”) per Objective-C/Swift. Se il valore è impostato tramite .xcconfig, verrà sostituito e sarà disponibile in Bundle main.infoDictionary. Questo metodo è preferibile a BuildConfigField (come in Android), poiché Info.plist è un meccanismo standard di iOS e i suoi valori sono disponibili per tutti i componenti di sistema, incluse estensioni, widget e Siri Intents.
Domande frequenti
User-Defined Setting è un parametro personalizzato aggiunto tramite l'interfaccia Build Settings. Funziona come .xcconfig, ma non può essere versionato, commentato o riutilizzato tra progetti. .xcconfig è un file su disco, User-Defined Setting è una voce in project.pbxproj.
Sì, CocoaPods genera file Pods-*.xcconfig per ogni configurazione. Questi file contengono le impostazioni per collegare i pod. Pods.xcconfig viene automaticamente collegato al tuo .xcconfig tramite #include nel file generatore. Non modificare Pods.xcconfig manualmente — viene sovrascritto durante pod install.
Tramite Info.plist: definisci un parametro in .xcconfig e usa $(PARAM) in Info.plist. Nel codice: Bundle.main.infoDictionary[“PARAM”]. Per i flag del preprocessore, usa SWIFT_ACTIVE_COMPILATION_CONDITIONS e #if CONDITION.
Motivi: hai modificato il valore nei Build Settings dell'interfaccia (l'interfaccia sovrascrive .xcconfig); il file non è collegato alla configurazione (verifica Project → Info → Configurations); percorso #include errato; errore di battitura nel nome del parametro. Diagnosi: xcodebuild -showBuildSettings mostrerà tutti i parametri attivi.
Sì, .xcconfig non dipende dal framework dell'interfaccia. Per i progetti SwiftUI, .xcconfig è altrettanto utile: gestire bundle ID, versioni, configurazioni ambientali, SWIFT_ACTIVE_COMPILATION_CONDITIONS per feature flags. SwiftUI non offre un'alternativa a .xcconfig, quindi si consiglia di utilizzarlo con qualsiasi progetto.
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