Active Compilation Conditionsは、ビルド時にコンパイラに渡されるフラグであり、最終的なバイナリファイルから特定のコードブロックを含めたり除外したりすることができます。Apple Developer Documentation(2026)によると、SwiftはOTHER_SWIFT_FLAGSキーと#ifディレクティブを通じてActive Compilation Conditionsをサポートしています。Active Compilation Conditionsにより、開発者はランタイムチェックなしで、デバッグ、テスト、本番用に異なるバージョンのコードをビルドできます。
重要なポイント
Active Compilation Conditionsは、ビルド時にアクティブなプリプロセッサディレクティブのセットを決定するコンパイルフラグです。ランタイムフラグ(if (isDebug)チェック)とは異なり、コンパイル条件はバイナリファイルから非アクティブなコードを物理的に除外するため、パフォーマンスが向上し、アプリケーションのサイズが削減されます。
このメカニズムはプリプロセッサまたはコンパイルの初期段階で動作します。コンパイラはアクティブな名前のリストを受け取り、#if NAMEディレクティブに遭遇すると、NAMEがそのリストにあるかどうかを確認します。名前が存在しない場合、ブロック内のコードは無視され、コンパイルされません。
Swift.org Blog(2025)によると、ランタイムフラグの代わりにActive Compilation Conditionsを使用すると、ログ記録とデバッグツールが充実したプロジェクトでは、リリースバイナリのサイズが平均12〜18%削減されます。これは、インストールファイルサイズに制限があるモバイルアプリケーションにとって特に重要です。
C / C ++ プリプロセッサレベルの条件付きコンパイルとの主な違いは、SwiftとKotlinのActive Compilation Conditionsが、テキスト置換レベルではなく、コンパイラのAST(抽象構文木)レベルで動作することです。これにより、より安全で予測可能になります。非アクティブな#ifブランチの構文エラーは、パース中に検出され、実行時に現れることはありません。
もう1つの重要な違いは、Swiftでは条件#if os(iOS) || os(macOS)がコンパイル時にチェックされ、プリプロセッサマクロではなくプラットフォーム名で動作することです。これにより、C / C ++ プリプロセッサで発生する可能性のある、#defineによる誤ったテキスト挿入に関連するバグのクラス全体が排除されます。Swiftコンパイラは置換されたテキストではなくASTを認識するため、条件付きコンパイルのデバッグが大幅に容易になります。
Swiftは#ifディレクティブを通じてActive Compilation Conditionsをサポートしており、論理演算子&&、||、!で組み合わせたフラグ名のリストを受け入れます。コンパイラは、条件がtrueの場合にのみ#if ... #endif内のコードを含めます。
Swiftにはいくつかの組み込み条件があります。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
開発者は、XcodeのBuild Setting OTHER_SWIFT_FLAGSを介して独自のフラグを追加できます。フラグはプレフィックス-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")。これらのフィールドは、各Build Variantごとに個別にBuildConfigクラスに生成されます。DEBUGフィールドは組み込み済みで、デバッグビルドでは自動的にtrueになります。
// 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は、主に4つのシナリオで使用されます。デバッグ(ログ、インスペクタ)、A/Bテスト(機能フラグ)、プラットフォーム適応(iOS/macOS共有コード)、ライセンス(無料版/有料版)です。
最も一般的なシナリオは、条件付きログ記録です。デバッグビルドでは、すべてのログがコンソールに書き込まれます。リリースビルドでは、何も記録されません。#if DEBUGまたはBuildConfig.DEBUGを使用すると、リリースバイナリにインライン化されたものでも、ロガーの呼び出しが1つも含まれていないことが保証されます。
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
新しい機能がまだ本番環境の準備ができていないが、コードにすでに存在する場合は、コンパイルフラグの背後に隠すことができます。ランタイム機能フラグとは異なり、コンパイルフラグはチェックでアプリケーションに負荷をかけず、ユーザーが有効にすることもできません。
Active Compilation Conditionsは控えめに使用する必要があります。フラグが多すぎると、コードが理解しにくくなります。開発者は、どのブランチが現時点でコンパイルされるかを確信できません。各フラグはREADMEまたは専用のCONFIG.mdファイルに文書化することをお勧めします。
分散チームを持つ大規模プロジェクトでは、CIでの自動フラグ検証を実装することが有用です。各プルリクエストは、Active Compilation Conditionsの可能なすべての組み合わせでビルドを通過する必要があります。これにより、非アクティブなフラグの下のコードがリファクタリングによって壊れておらず、リリースまで条件付きコンパイルブランチがテストされないままになっていないことが保証されます。xcresulttool(iOS用)やGradle Build Scan(Android用)などのツールは、このプロセスを自動化するのに役立ちます。
よくある質問
#if DEBUGはコンパイルディレクティブです。DEBUGがアクティブでない場合、ブロック内のコードはバイナリに含まれません。if (isDebug)はランタイムチェックです。コードは常にコンパイルされ、条件は実行時にチェックされます。#ifはリリースビルドに痕跡を残しません。
プロジェクトの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は2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。