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 文件中的 .targetswiftSettings 参数中执行此操作。使用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 - 设置应用程序图角标

swift 标-Syntex.swift

xcode中的 preprocessor macros

使目标名称 Swift 标志在 UITests 模块中可见(Swift 5)

贝宝系统错误 (DCC_PREPROCESSOR_ERROR)

Hypertext Preprocessor