Active Compilation Conditions — це прапорці, які передаються компілятору на етапі збірки та дозволяють включати або виключати певні блоки коду з фінального бінарного файлу. За даними Apple Developer Documentation (2026), Swift підтримує Active Compilation Conditions через ключ OTHER_SWIFT_FLAGS та директиву #if. Active Compilation Conditions дають розробникам можливість збирати різні версії коду для налагодження, тестування та продакшену без перевірок під час виконання.
Головне
Active Compilation Conditions — це прапорці компіляції, які визначають набір активних директив препроцесора на етапі збірки. На відміну від прапорців часу виконання (перевірка if (isDebug)), умови компіляції фізично виключають неактивний код із бінарного файлу, що дає приріст продуктивності та зменшує розмір застосунку.
Механізм працює на рівні препроцесора або ранніх фаз компіляції: компілятор отримує список активних імен і при зустрічі з директивою #if NAME перевіряє, чи є NAME у цьому списку. Якщо імені немає — код всередині блоку ігнорується та не компілюється.
За даними Swift.org Blog (2025), використання Active Compilation Conditions замість прапорців часу виконання скорочує розмір release-бінарника в середньому на 12-18% для проєктів із розвиненою системою логування та налагоджувальних інструментів. Це особливо критично для мобільних застосунків з обмеженнями за розміром інсталяційного файлу.
Основна відмінність від умовної компіляції на рівні препроцесора C/C++ — Active Compilation Conditions у Swift та Kotlin працюють на рівні компілятора AST (Abstract Syntax Tree), а не на рівні текстової заміни. Це робить їх безпечнішими та передбачуванішими: будь-яка синтаксична помилка в неактивній гілці #if буде виявлена на етапі парсингу, а не проявиться під час виконання.
Ще одна важлива відмінність — у Swift умова #if os(iOS) || os(macOS) перевіряється на етапі компіляції та працює з іменами платформ, а не з макросами препроцесора. Це виключає цілий клас багів, пов'язаних із неправильним вставленням тексту через #define, які можливі в препроцесорі C/C++. Компілятор Swift бачить AST, а не замінений текст, що робить налагодження умовної компіляції значно простішим.
Swift підтримує Active Compilation Conditions через директиву #if, яка приймає список імен прапорців, об'єднаних логічними операторами &&, || та !. Компілятор включає код всередині #if ... #endif лише якщо умова істинна.
Swift надає кілька вбудованих умов: DEBUG (автоматично активний у debug-збірці), swift(>=5.0) (перевірка версії компілятора), canImport(UIKit) (перевірка доступності модуля) та targetEnvironment(simulator) (перевірка середовища). Ці умови не потребують додаткового налаштування.
// Вбудовані умови Swift
#if DEBUG
print("Налагоджувальна збірка — логування активне")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Розробник може додавати свої прапорці через Build Setting OTHER_SWIFT_FLAGS у Xcode. Прапорець вказується з префіксом -D, наприклад -DBETA або -DANALYTICS_ENABLED. Для різних конфігурацій (Debug, Release, Staging) можна встановити різні набори прапорців.
// Обробка свого прапорця 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 підтримує платформені умови: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Ці умови перевіряють цільову платформу збірки та дозволяють писати код, спільний для кількох платформ Apple, із платформо-специфічними блоками.
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
}
В екосистемі Android Active Compilation Conditions реалізовані через систему BuildConfig, productFlavors та прапорці в build.gradle.kts. Kotlin не має прямого аналога директиви #if на рівні мови, але надає альтернативні механізми.
Найпоширеніший спосіб — додати buildConfigField для кожного прапорця: buildConfigField("boolean", "BETA", "true"). Ці поля генеруються в клас BuildConfig для кожного Build Variant окремо. Поле DEBUG уже вбудоване та автоматично true для debug-збірок.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Використання в коді Kotlin
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle дозволяє створювати окремі директорії sourceSets для кожного флейвору. Наприклад, src/demo/ та src/full/. Класи з однаковим іменем у різних sourceSets замінюють один одного при збірці відповідного флейвору. Це потужніший механізм, ніж прапорці, тому що можна перевизначати цілі класи.
// 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
}
Для Kotlin Multiplatform (KMP) доступна директива expect/actual, яка дозволяє оголошувати очікувані оголошення у спільному коді та надавати платформені реалізації. Це механізм рівня компіляції, аналогічний Active Compilation Conditions за ефектом — неактивний код не компілюється для непідходящих платформ.
Active Compilation Conditions застосовуються в чотирьох основних сценаріях: налагодження (логи, інспектори), A/B тестування (прапорці функцій), платформена адаптація (iOS/macOS спільний код) та ліцензування (безкоштовна/платна версії).
Найчастіший сценарій — умовне логування. У debug-збірці всі логи пишуться в консоль, у release — нічого. Використання #if DEBUG або BuildConfig.DEBUG гарантує, що release-бінарник не містить жодного виклику логера, навіть заінлайненного.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Якщо нова функціональність ще не готова для продакшену, але вже є в коді, її можна приховати за прапорцем компіляції. На відміну від runtime feature flags, прапорці компіляції не навантажують застосунок перевірками та не можуть бути увімкнені користувачем.
Active Compilation Conditions слід використовувати помірно. Надмірна кількість прапорців робить код важким для розуміння: розробник не може бути впевненим, які гілки скомпілюються в даний момент. Рекомендується документувати кожен прапорець у README або спеціальному файлі CONFIG.md.
У великих проєктах із розподіленою командою корисно впровадити автоматичну валідацію прапорців у CI. Кожен pull request має проходити збірку з усіма можливими комбінаціями Active Compilation Conditions. Це гарантує, що код під неактивним прапорцем не зламався через рефакторинг, і жодна гілка умовної компіляції не залишилася неперевіреною до моменту релізу. Інструменти на кшталт xcresulttool (для iOS) та Gradle Build Scan (для Android) допомагають автоматизувати цей процес.
Часті запитання
#if DEBUG — це директива компіляції: якщо DEBUG не активний, код всередині блоку не потрапляє в бінарник. if (isDebug) — перевірка під час виконання: код компілюється завжди, умова перевіряється під час виконання. #if не залишає слідів у release-збірці.
У Build Settings проєкту знайти Other Swift Flags (OTHER_SWIFT_FLAGS) і додати новий рядок із прапорцем: -DMY_FLAG. Прапорець буде видимий директиві #if MY_FLAG. Можна встановити різні прапорці для Debug та Release конфігурацій.
У Kotlin/JVM немає прямого аналога. Натомість використовуються поля BuildConfig (перевірка під час виконання, але ProGuard може викинути невикористовуваний код). У Kotlin Multiplatform — директива expect/actual на рівні оголошень.
Так, Swift підтримує логічні оператори: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Умови можна групувати дужками для складної логіки. AND та OR працюють за стандартними правилами короткого замикання.
SwiftUI прев'ю збираються в окремому процесі з прапорцями, відмінними від основного таргета. DEBUG може бути не активний. Рішення: використовувати targetEnvironment(simulator) для коду прев'ю або виносити умовну логіку в окремі методи.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також