Les Active Compilation Conditions sont des drapeaux transmis au compilateur lors de la phase de construction qui permettent d'inclure ou d'exclure des blocs de code spécifiques du fichier binaire final. Selon la Documentation Apple Developer (2026), Swift prend en charge les Active Compilation Conditions via la clé OTHER_SWIFT_FLAGS et la directive #if. Active Compilation Conditions offrent aux développeurs la possibilité de construire différentes versions de code pour le débogage, les tests et la production sans vérifications à l'exécution.
Points clés
Active Compilation Conditions sont des drapeaux de compilation qui déterminent l'ensemble des directives de préprocesseur actives lors de la construction. Contrairement aux drapeaux d'exécution (vérification if (isDebug)), les conditions de compilation excluent physiquement le code inactif du fichier binaire, ce qui offre des gains de performance et réduit la taille de l'application.
Le mécanisme opère au niveau du préprocesseur ou des phases précoces de compilation : le compilateur reçoit une liste de noms actifs et, lorsqu'il rencontre la directive #if NAME, vérifie si NAME est dans cette liste. Si le nom n'est pas présent, le code à l'intérieur du bloc est ignoré et non compilé.
Selon le Blog Swift.org (2025), l'utilisation des Active Compilation Conditions au lieu des drapeaux d'exécution réduit la taille du binaire de release en moyenne de 12 à 18 % pour les projets disposant d'un système étendu de journalisation et d'outils de débogage. C'est particulièrement critique pour les applications mobiles avec des limitations de taille de fichier d'installation.
La principale différence par rapport à la compilation conditionnelle au niveau du préprocesseur C/C++ est que les Active Compilation Conditions en Swift et Kotlin opèrent au niveau de l'AST (Arbre Syntaxique Abstrait) du compilateur, et non au niveau du remplacement de texte. Cela les rend plus sûres et plus prévisibles : toute erreur de syntaxe dans une branche #if inactive sera détectée lors de l'analyse, et ne se manifestera pas à l'exécution.
Une autre différence importante est qu'en Swift, la condition #if os(iOS) || os(macOS) est vérifiée à la compilation et fonctionne avec des noms de plateforme, et non avec des macros de préprocesseur. Cela élimine toute une classe de bugs liés à l'insertion incorrecte de texte via #define, possibles dans le préprocesseur C/C++. Le compilateur Swift voit l'AST, pas le texte remplacé, ce qui rend le débogage de la compilation conditionnelle considérablement plus facile.
Swift prend en charge les Active Compilation Conditions via la directive #if, qui accepte une liste de noms de drapeaux combinés avec des opérateurs logiques &&, || et !. Le compilateur inclut le code à l'intérieur de #if ... #endif uniquement si la condition est vraie.
Swift fournit plusieurs conditions intégrées : DEBUG (automatiquement actif dans les constructions de débogage), swift(>=5.0) (vérification de version du compilateur), canImport(UIKit) (vérification de disponibilité du module) et targetEnvironment(simulator) (vérification d'environnement). Ces conditions ne nécessitent aucune configuration supplémentaire.
// Conditions intégrées de Swift
#if DEBUG
print("Construction de débogage — journalisation active")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Les développeurs peuvent ajouter leurs propres drapeaux via le paramètre de construction OTHER_SWIFT_FLAGS dans Xcode. Le drapeau est spécifié avec le préfixe -D, par exemple -DBETA ou -DANALYTICS_ENABLED. Différents ensembles de drapeaux peuvent être configurés pour différentes configurations (Debug, Release, Staging).
// Gestion du drapeau personnalisé BETA
#if BETA
let apiEndpoint = "https://beta.api.com"
let isLoggingEnabled = true
#else
let apiEndpoint = "https://api.com"
let isLoggingEnabled = false
#endif
func trackEvent(_ name: String) {
#if ANALYTICS_ENABLED
Analytics.log(name)
#endif
}
Swift prend en charge les conditions de plateforme : os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Ces conditions vérifient la plateforme de construction cible et permettent d'écrire du code partagé entre plusieurs plateformes Apple avec des blocs spécifiques à la plateforme.
import Foundation
func getDeviceName() -> String {
#if os(iOS)
return UIDevice.current.name
#elseif os(macOS)
return Host.current.name ?? "Unknown"
#else
return "Other platform"
#endif
}
Dans l'écosystème Android, les Active Compilation Conditions sont implémentées via le système BuildConfig, productFlavors et les drapeaux dans build.gradle.kts. Kotlin n'a pas d'équivalent direct de la directive #if au niveau du langage mais fournit des mécanismes alternatifs.
L'approche la plus courante consiste à ajouter un buildConfigField pour chaque drapeau : buildConfigField("boolean", "BETA", "true"). Ces champs sont générés dans la classe BuildConfig pour chaque variante de construction séparément. Le champ DEBUG est déjà intégré et automatiquement vrai pour les constructions de débogage.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Utilisation dans le code Kotlin
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle permet de créer des répertoires sourceSets séparés pour chaque variante. Par exemple, src/demo/ et src/full/. Les classes avec le même nom dans différents sourceSets se remplacent mutuellement lors de la construction de la variante correspondante. C'est un mécanisme plus puissant que les drapeaux car des classes entières peuvent être redéfinies.
// src/demo/java/com/example/Config.kt
object Config {
const val API_URL = "http://demo.api.com"
const val IS_BETA = true
}
// src/full/java/com/example/Config.kt
object Config {
const val API_URL = "https://full.api.com"
const val IS_BETA = false
}
Pour Kotlin Multiplatform (KMP), la directive expect/actual est disponible, qui permet de déclarer des déclarations attendues dans le code commun et de fournir des implémentations spécifiques à la plateforme. C'est un mécanisme au niveau du compilateur similaire en effet aux Active Compilation Conditions — le code inactif n'est pas compilé pour les plateformes non adaptées.
Les Active Compilation Conditions sont utilisées dans quatre scénarios principaux : débogage (journaux, inspecteurs), tests A/B (drapeaux de fonctionnalités), adaptation de plateforme (code partagé iOS/macOS) et licences (versions gratuites/payantes).
Le scénario le plus courant est la journalisation conditionnelle. Dans les constructions de débogage, tous les journaux sont écrits dans la console ; dans les constructions de release, rien n'est journalisé. L'utilisation de #if DEBUG ou BuildConfig.DEBUG garantit que le binaire de release ne contient pas un seul appel de journaliseur, même ceux inline.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Si une nouvelle fonctionnalité n'est pas encore prête pour la production mais existe déjà dans le code, elle peut être cachée derrière un drapeau de compilation. Contrairement aux drapeaux de fonctionnalités d'exécution, les drapeaux de compilation ne surchargent pas l'application avec des vérifications et ne peuvent pas être activés par l'utilisateur.
Les Active Compilation Conditions doivent être utilisées avec parcimonie. Un nombre excessif de drapeaux rend le code difficile à comprendre : le développeur ne peut pas être sûr quelles branches seront compilées à un moment donné. Il est recommandé de documenter chaque drapeau dans le README ou un fichier CONFIG.md dédié.
Dans les grands projets avec des équipes distribuées, il est utile d'implémenter une validation automatique des drapeaux dans le CI. Chaque pull request doit passer la construction avec toutes les combinaisons possibles d'Active Compilation Conditions. Cela garantit que le code sous un drapeau inactif ne s'est pas cassé à cause d'un refactoring, et qu'aucune branche de compilation conditionnelle ne reste non testée jusqu'à la release. Des outils comme xcresulttool (pour iOS) et Gradle Build Scan (pour Android) aident à automatiser ce processus.
Foire aux questions
#if DEBUG est une directive de compilation : si DEBUG n'est pas actif, le code à l'intérieur du bloc n'entre pas dans le binaire. if (isDebug) est une vérification à l'exécution : le code est toujours compilé, la condition est vérifiée lors de l'exécution. #if ne laisse aucune trace dans la construction de release.
Dans les paramètres de construction du projet, trouvez Other Swift Flags (OTHER_SWIFT_FLAGS) et ajoutez une nouvelle ligne avec le drapeau : -DMY_FLAG. Le drapeau sera visible par la directive #if MY_FLAG. Différents drapeaux peuvent être définis pour les configurations Debug et Release.
Kotlin/JVM n'a pas d'équivalent direct. À la place, des champs BuildConfig sont utilisés (vérification à l'exécution, mais ProGuard peut supprimer le code inutilisé). Dans Kotlin Multiplatform — la directive expect/actual au niveau des déclarations.
Oui, Swift prend en charge les opérateurs logiques : #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Les conditions peuvent être regroupées entre parenthèses pour une logique complexe. AND et OR fonctionnent selon les règles standard de court-circuit.
Les aperçus SwiftUI sont compilés dans un processus séparé avec des drapeaux différents de la cible principale. DEBUG peut ne pas être actif. Solution : utilisez targetEnvironment(simulator) pour le code d'aperçu ou extrayez la logique conditionnelle dans des méthodes séparées.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi