Swift:如何使用 PREPROCESSOR 标志(如`#if DEBUG`)来实现 API 密钥?
Posted
技术标签:
【中文标题】Swift:如何使用 PREPROCESSOR 标志(如`#if DEBUG`)来实现 API 密钥?【英文标题】:Swift: how to use PREPROCESSOR Flags (like `#if DEBUG`) to implement API keys? 【发布时间】:2016-12-13 07:48:48 【问题描述】:在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 编译器不再使用预处理器?
【问题讨论】:
【参考方案1】:Apple 从Xcode 8 开始全面支持 Swift 预处理器标志,因此不再需要在“Other Swift Flags”中设置这些值。
新设置称为“活动编译条件”,它为 Swift 等效的预处理器标志提供***支持。使用它的方式与使用“Other Swift Flags”完全相同,只是不需要在值前面加上“-D”(这样会更简洁一些)。
来自Xcode 8 release notes:
Active Compilation Conditions
是一个新的构建设置,用于将条件编译标志传递给 Swift 编译器。此设置的值的每个元素都以-D
为前缀传递给swiftc,就像Preprocessor Macros
的元素以相同的前缀传递给clang。 (22457329)
您可以像这样使用上述设置:
#if DEBUG
let accessToken = "DebugAccessToken"
#else
let accessToken = "ProductionAccessToken"
#endif
【讨论】:
注意:您应该不指定 =1 或任何其他 = 值。相反,您只需要指定标志名称。 :] @JRG-Developer 我不反对,但我不确定您的评论如何适用于此。 这是一个有用的答案,但来自 Objective-C 背景(我想许多 ios 开发人员都是),我认为我需要指定=1
... 我失去了一点时间试图弄清楚为什么当我这样做时它不起作用。所以,我想我会分享这个花絮来帮助下一个人。 :] 无论如何,在这里感谢您的回答!
@JRG-Developer, @Dan Loewenherz 我在Active Compilation Conditions
中设置了DEBUG
,在Preprocessor Macros
中设置了DEBUG=1
,但此配置根本不起作用。我应该删除DEBUG=1
吗?从上面的 cmets 看不清楚。
@DanLoewenherz 你是完全正确的。我在目标设置中为存档配置设置了“DEBUG”,因此每次它运行调试语句并且从不运行发布条件。任何遇到问题的人请先检查您的目标Build Configuration
。查看此答案***.com/questions/9063100/… 了解更多信息。【参考方案2】:
更新:Xcode 8 现在自动支持此功能,请参阅上面@DanLoewenherz 的回复。
在 Xcode 8 之前,您仍然可以以相同的方式使用宏:
#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif
但是,为了让 Swift 获取它们,您需要在目标的 Build Settings 中设置“Other Swift Flags”:
为您的目标打开构建设置 搜索“其他 swift 标志” 添加您希望使用的宏,前面带有-D
标志
【讨论】:
你成就了我的一天!对我来说,没有-D
前缀是行不通的【参考方案3】:
作为后续观察,尽量不要将 api 密钥/秘密以明文形式保存在存储库中。使用秘密管理系统将密钥/秘密加载到用户的环境变量中。否则,如果可以接受,则必须执行第 1 步。
-
将“秘密”放在上述封闭存储库中的纯文本文件中
创建一个包含
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
【讨论】:
【参考方案4】:在 swift 包中,您必须在 Package.swift
文件中的 .target
的 swiftSettings
参数中执行此操作。使用define
方法(Apple documentation)或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
【讨论】:
以上是关于Swift:如何使用 PREPROCESSOR 标志(如`#if DEBUG`)来实现 API 密钥?的主要内容,如果未能解决你的问题,请参考以下文章
使目标名称 Swift 标志在 UITests 模块中可见(Swift 5)