Swift:如何使用 PREPROCESSOR 标志(如 `#if DEBUG`)来实现 API 键?
Swift: how to use PREPROCESSOR Flags (like `#if DEBUG`) to implement API keys?
在 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 编译器不再使用预处理器?
更新:Xcode 8 现在自动支持此功能,请参阅上面@DanLoewenherz 的回复。
在 Xcode8 之前,您仍然可以以相同的方式使用宏:
#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif
然而,为了让它们被 Swift 拾取,您需要在目标的构建设置中设置 "Other Swift Flags":
- 打开目标的构建设置
- 搜索 "other swift flags"
- 添加您希望使用的宏,前面加上
-D
标志
Apple 从 Xcode 8 开始全面支持 Swift 预处理器标志,因此不再需要在“其他 Swift 标志”中设置这些值。
新设置称为“活动编译条件”,它为预处理器标志的 Swift 等价物提供顶级支持。您使用它的方式与使用“其他 Swift 标志”的方式完全相同,只是不需要在值前加上“-D”(因此它更简洁)。
Active Compilation Conditions
is a new build setting for passing conditional compilation flags to the Swift compiler. Each element of the value of this setting passes to swiftc prefixed with -D
, in the same way that elements of Preprocessor Macros
pass to clang with the same prefix. (22457329)
你像这样使用上面的设置:
#if DEBUG
let accessToken = "DebugAccessToken"
#else
let accessToken = "ProductionAccessToken"
#endif
作为后续观察,尽量不要在存储库中以明文形式保存 api 密钥/秘密。使用机密管理系统将密钥/机密加载到用户的环境变量中。否则,如果可以接受,第 1 步是必要的。
- 将 "secrets" 放在上面的封闭存储库中的纯文本文件中
- 创建一个包含
export API_KEY_A='<plaintext_key_aef94c5l6>'
列表的 ../set_keys.sh
(使用单引号防止求值)
- 添加一个运行脚本阶段,可以
source ../set_keys.sh
并将其移动到执行顺序的顶部
- 在 Build Settings > Preprocessor Macros 中,根据需要添加定义,例如
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
在 swift 包中,您必须在 Package.swift
文件中 .target
的 swiftSettings
参数内执行此操作。使用define
方法(Apple documentation) or Swift 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
在 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 编译器不再使用预处理器?
更新:Xcode 8 现在自动支持此功能,请参阅上面@DanLoewenherz 的回复。
在 Xcode8 之前,您仍然可以以相同的方式使用宏:
#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif
然而,为了让它们被 Swift 拾取,您需要在目标的构建设置中设置 "Other Swift Flags":
- 打开目标的构建设置
- 搜索 "other swift flags"
- 添加您希望使用的宏,前面加上
-D
标志
Apple 从 Xcode 8 开始全面支持 Swift 预处理器标志,因此不再需要在“其他 Swift 标志”中设置这些值。
新设置称为“活动编译条件”,它为预处理器标志的 Swift 等价物提供顶级支持。您使用它的方式与使用“其他 Swift 标志”的方式完全相同,只是不需要在值前加上“-D”(因此它更简洁)。
Active Compilation Conditions
is a new build setting for passing conditional compilation flags to the Swift compiler. Each element of the value of this setting passes to swiftc prefixed with-D
, in the same way that elements ofPreprocessor Macros
pass to clang with the same prefix. (22457329)
你像这样使用上面的设置:
#if DEBUG
let accessToken = "DebugAccessToken"
#else
let accessToken = "ProductionAccessToken"
#endif
作为后续观察,尽量不要在存储库中以明文形式保存 api 密钥/秘密。使用机密管理系统将密钥/机密加载到用户的环境变量中。否则,如果可以接受,第 1 步是必要的。
- 将 "secrets" 放在上面的封闭存储库中的纯文本文件中
- 创建一个包含
export API_KEY_A='<plaintext_key_aef94c5l6>'
列表的../set_keys.sh
(使用单引号防止求值) - 添加一个运行脚本阶段,可以
source ../set_keys.sh
并将其移动到执行顺序的顶部 - 在 Build Settings > Preprocessor Macros 中,根据需要添加定义,例如
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
在 swift 包中,您必须在 Package.swift
文件中 .target
的 swiftSettings
参数内执行此操作。使用define
方法(Apple documentation) or Swift 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