Swift: 如何使用预处理器标志(如‘ # if DEBUG’)来实现 API 键?

Objective-C中,有时候使用静态字符串常量来定义替代 API 键是有用的(例如,在分析包中区分 RELEASE 和 DEBUG 键,比如 MixPanel、 Flurry 或 Crashlytics) :

#if DEBUG
static NSString *const API_KEY = @"KEY_A";
#else
static NSString *const API_KEY = @"KEY_B";
#endif

然后..。

[Analytics startSession:API_KEY];

既然 Swift 编译器不再使用预处理器,那么如何将其转换为 Swift 呢?

79092 次浏览

UPDATED: Xcode 8 now supports this automatically, see @dwlz's response above.

在 Xcode 8之前,您仍然可以以相同的方式使用宏:

#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif

然而,为了让它们被 Swift 拾取,你需要在目标的构建设置中设置“其他 Swift 标志”:

  • 打开目标的“生成设置”
  • 搜索“其他快旗”
  • 添加您希望使用的宏,前面加上 -D标志

enter image description here

苹果在 Xcode 8中包含了对 Swift 预处理器标志的完全支持,所以不再需要在“其他 Swift 标志”中设置这些值。

新的设置称为“活动编译条件”,它为 Swift 等效的预处理器标志提供顶级支持。您使用它的方式与使用“ Other Swift Flags”的方式完全相同,只是不需要在值前面加上一个“-D”(所以它更干净一些)。

来自 Xcode 8发布说明:

Active Compilation Conditions是一个新的生成设置,用于将条件编译标志传递给 Swift 编译器。这个设置的值的每个元素都传递给带有 -D前缀的 Swiftc,就像 Preprocessor Macros的元素传递给带有相同前缀的叮当声一样。(22457329)

enter image description here

你可以这样使用上面的设置:

#if DEBUG
let accessToken = "DebugAccessToken"
#else
let accessToken = "ProductionAccessToken"
#endif

作为后续观察,尽量不要在存储库中以明文形式保留 api 密钥/机密。使用机密管理系统将密钥/机密加载到用户的环境变量中。否则,如果可以接受,第1步是必要的。

  1. 将“机密”放在上面的一个明文文件中,放在封闭的存储库中
  2. 创建一个包含 export API_KEY_A='<plaintext_key_aef94c5l6>'列表的 ../set_keys.sh(使用单引号以防止计算)
  3. 添加一个可以执行 source ../set_keys.sh的 Run 脚本阶段,并将其移动到执行顺序的顶部
  4. 在构建设置 > 预处理器宏中,根据需要添加定义,如 API_KEY_A="$API_KEY_A"

它将环境变量捕获到编译器定义中,然后在每个源文件的 clang 调用中使用该定义。

目录结构示例

[10:33:15] ~/code/memo yes? tree -L 2 .
.
├── Memo
│   ├── Memo
│   ├── Memo.xcodeproj
│   ├── Memo.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   └── Pods
└── keys

在快速包中,您必须在 Package.swift文件中的 swiftSettings参数中对 .target执行此操作。使用 define方法 (Apple documentation)快速文档

targets: [
.target(name: String,
dependencies: [Target.Dependency],
path: String?,
exclude: [String]?,
sources: [String]?,,
cSettings: [CSetting]?,
cxxSettings: [CXXSetting]?,
swiftSettings: [SwiftSetting]?,
linkerSettings: [LinkerSetting]?),

我的看起来像这样,它的工作!

            swiftSettings: [
.define("VAPOR")
]

在我的代码中,我可以有条件地使用以下代码进行编译:

#if VAPOR