Active Compilation Conditions là các cờ được truyền cho trình biên dịch trong giai đoạn xây dựng và cho phép bao gồm hoặc loại trừ các khối mã cụ thể khỏi tệp nhị phân cuối cùng. Theo Tài liệu Apple Developer (2026), Swift hỗ trợ Active Compilation Conditions thông qua khóa OTHER_SWIFT_FLAGS và chỉ thị #if. Active Compilation Conditions cho phép các nhà phát triển xây dựng các phiên bản mã khác nhau để gỡ lỗi, kiểm thử và sản xuất mà không cần kiểm tra thời gian chạy.
Những điểm chính
Active Compilation Conditions là các cờ biên dịch xác định tập hợp các chỉ thị tiền xử lý hoạt động tại thời điểm xây dựng. Không giống như cờ thời gian chạy (kiểm tra if (isDebug)), các điều kiện biên dịch loại trừ vật lý mã không hoạt động khỏi tệp nhị phân, mang lại lợi ích về hiệu suất và giảm kích thước ứng dụng.
Cơ chế hoạt động ở cấp độ tiền xử lý hoặc các giai đoạn đầu của quá trình biên dịch: trình biên dịch nhận danh sách các tên đang hoạt động và khi gặp chỉ thị #if NAME, sẽ kiểm tra xem NAME có trong danh sách đó không. Nếu tên không có, mã bên trong khối sẽ bị bỏ qua và không được biên dịch.
Theo Blog Swift.org (2025), việc sử dụng Active Compilation Conditions thay vì cờ thời gian chạy giúp giảm kích thước tệp nhị phân phát hành trung bình 12-18% cho các dự án có hệ thống ghi nhật ký và công cụ gỡ lỗi mở rộng. Điều này đặc biệt quan trọng đối với các ứng dụng di động có hạn chế về kích thước tệp cài đặt.
Sự khác biệt chính so với biên dịch có điều kiện ở cấp độ tiền xử lý C/C++ là Active Compilation Conditions trong Swift và Kotlin hoạt động ở cấp độ AST (Cây cú pháp trừu tượng) của trình biên dịch, chứ không phải ở cấp độ thay thế văn bản. Điều này làm cho chúng an toàn hơn và dễ dự đoán hơn: bất kỳ lỗi cú pháp nào trong nhánh #if không hoạt động sẽ được phát hiện trong quá trình phân tích cú pháp, chứ không xuất hiện tại thời gian chạy.
Một điểm khác biệt quan trọng nữa là trong Swift, điều kiện #if os(iOS) || os(macOS) được kiểm tra tại thời điểm biên dịch và hoạt động với tên nền tảng, chứ không phải với macro tiền xử lý. Điều này loại bỏ toàn bộ một lớp lỗi liên quan đến việc chèn văn bản không chính xác thông qua #define, có thể xảy ra trong tiền xử lý C/C++. Trình biên dịch Swift nhìn thấy AST chứ không phải văn bản đã thay thế, giúp việc gỡ lỗi biên dịch có điều kiện dễ dàng hơn đáng kể.
Swift hỗ trợ Active Compilation Conditions thông qua chỉ thị #if, chấp nhận danh sách các tên cờ kết hợp với toán tử logic &&, || và !. Trình biên dịch chỉ bao gồm mã bên trong #if ... #endif nếu điều kiện là đúng.
Swift cung cấp một số điều kiện tích hợp: DEBUG (tự động hoạt động trong bản dựng gỡ lỗi), swift(>=5.0) (kiểm tra phiên bản trình biên dịch), canImport(UIKit) (kiểm tra khả dụng mô-đun) và targetEnvironment(simulator) (kiểm tra môi trường). Các điều kiện này không yêu cầu cấu hình bổ sung.
// Các điều kiện tích hợp của Swift
#if DEBUG
print("Bản dựng gỡ lỗi — ghi nhật ký hoạt động")
#endif
#if canImport(UIKit)
import UIKit
let screen = UIScreen.main.bounds
#elseif canImport(AppKit)
import AppKit
let screen = NSScreen.main?.frame
#endif
Nhà phát triển có thể thêm cờ riêng của họ thông qua Cài đặt Xây dựng OTHER_SWIFT_FLAGS trong Xcode. Cờ được chỉ định với tiền tố -D, ví dụ -DBETA hoặc -DANALYTICS_ENABLED. Các bộ cờ khác nhau có thể được đặt cho các cấu hình khác nhau (Debug, Release, Staging).
// Xử lý cờ BETA tùy chỉnh
#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 hỗ trợ các điều kiện nền tảng: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Các điều kiện này kiểm tra nền tảng xây dựng mục tiêu và cho phép viết mã chia sẻ trên nhiều nền tảng Apple với các khối dành riêng cho nền tảng.
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
}
Trong hệ sinh thái Android, Active Compilation Conditions được triển khai thông qua hệ thống BuildConfig, productFlavors và các cờ trong build.gradle.kts. Kotlin không có tương đương trực tiếp của chỉ thị #if ở cấp độ ngôn ngữ nhưng cung cấp các cơ chế thay thế.
Cách phổ biến nhất là thêm buildConfigField cho mỗi cờ: buildConfigField("boolean", "BETA", "true"). Các trường này được tạo trong lớp BuildConfig riêng cho mỗi Biến thể Xây dựng. Trường DEBUG đã được tích hợp sẵn và tự động là true cho các bản dựng gỡ lỗi.
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("boolean", "BETA", "true")
}
release {
buildConfigField("boolean", "BETA", "false")
}
}
}
// Sử dụng trong mã Kotlin
if (BuildConfig.BETA) {
enableBetaFeatures()
}
Gradle cho phép tạo các thư mục sourceSets riêng biệt cho mỗi hương vị. Ví dụ: src/demo/ và src/full/. Các lớp có cùng tên trong các sourceSets khác nhau sẽ thay thế lẫn nhau khi xây dựng hương vị tương ứng. Đây là một cơ chế mạnh mẽ hơn cờ vì toàn bộ lớp có thể được ghi đè.
// 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
}
Đối với Kotlin Multiplatform (KMP), chỉ thị expect/actual có sẵn, cho phép khai báo các khai báo dự kiến trong mã chung và cung cấp các triển khai dành riêng cho nền tảng. Đây là cơ chế cấp trình biên dịch tương tự về hiệu quả với Active Compilation Conditions — mã không hoạt động không được biên dịch cho các nền tảng không phù hợp.
Active Compilation Conditions được sử dụng trong bốn tình huống chính: gỡ lỗi (nhật ký, trình kiểm tra), kiểm thử A/B (cờ tính năng), thích ứng nền tảng (mã chia sẻ iOS/macOS) và cấp phép (phiên bản miễn phí/trả phí).
Tình huống phổ biến nhất là ghi nhật ký có điều kiện. Trong bản dựng gỡ lỗi, tất cả nhật ký được ghi vào bảng điều khiển; trong bản dựng phát hành, không có gì được ghi lại. Sử dụng #if DEBUG hoặc BuildConfig.DEBUG đảm bảo rằng tệp nhị phân phát hành không chứa một lệnh gọi logger nào, kể cả các lệnh được nội dòng.
func logRequest(_ url: URL, _ statusCode: Int) {
#if DEBUG
Logger.debug("Request to \(url.absoluteString) returned \(statusCode)")
#endif
}
Nếu một tính năng mới chưa sẵn sàng cho sản xuất nhưng đã có trong mã, nó có thể được ẩn sau một cờ biên dịch. Không giống như cờ tính năng thời gian chạy, cờ biên dịch không gây tải cho ứng dụng bằng các kiểm tra và không thể được kích hoạt bởi người dùng.
Active Compilation Conditions nên được sử dụng một cách tiết kiệm. Số lượng cờ quá nhiều làm cho mã khó hiểu: nhà phát triển không thể chắc chắn nhánh nào sẽ được biên dịch tại một thời điểm nhất định. Nên ghi lại từng cờ trong README hoặc tệp CONFIG.md chuyên dụng.
Trong các dự án lớn với nhóm phân tán, việc triển khai xác thực cờ tự động trong CI rất hữu ích. Mỗi yêu cầu kéo phải vượt qua bản dựng với tất cả các kết hợp có thể có của Active Compilation Conditions. Điều này đảm bảo rằng mã dưới cờ không hoạt động không bị hỏng do tái cấu trúc và không có nhánh biên dịch có điều kiện nào không được kiểm tra cho đến khi phát hành. Các công cụ như xcresulttool (cho iOS) và Gradle Build Scan (cho Android) giúp tự động hóa quy trình này.
Câu hỏi thường gặp
#if DEBUG là một chỉ thị biên dịch: nếu DEBUG không hoạt động, mã bên trong khối không đi vào tệp nhị phân. if (isDebug) là kiểm tra thời gian chạy: mã luôn được biên dịch, điều kiện được kiểm tra tại thời gian chạy. #if không để lại dấu vết trong bản dựng phát hành.
Trong Cài đặt Xây dựng của dự án, tìm Other Swift Flags (OTHER_SWIFT_FLAGS) và thêm một dòng mới với cờ: -DMY_FLAG. Cờ sẽ hiển thị cho chỉ thị #if MY_FLAG. Có thể đặt các cờ khác nhau cho cấu hình Debug và Release.
Kotlin/JVM không có tương đương trực tiếp. Thay vào đó, trường BuildConfig được sử dụng (kiểm tra thời gian chạy, nhưng ProGuard có thể loại bỏ mã không sử dụng). Trong Kotlin Multiplatform — chỉ thị expect/actual ở cấp độ khai báo.
Có, Swift hỗ trợ toán tử logic: #if DEBUG && BETA, #if os(iOS) || os(tvOS), #if !RELEASE. Các điều kiện có thể được nhóm trong ngoặc đơn cho logic phức tạp. AND và OR hoạt động theo quy tắc rút gọn tiêu chuẩn.
Bản xem trước SwiftUI được xây dựng trong một quy trình riêng với các cờ khác với mục tiêu chính. DEBUG có thể không hoạt động. Giải pháp: sử dụng targetEnvironment(simulator) cho mã xem trước hoặc trích xuất logic có điều kiện vào các phương thức riêng.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm