Swift:如何使用PREPROCESSOR Flags(如`#if DEBUG`)来实现API密钥?

cle*_*bit 67 macros xcode preprocessor swift

Objective-C它是使用静态字符串常量来定义备用API键(例如发布和调试键之间进行区分用于分析套件,像MixPanel,乱舞或Crashlytics)有时是有用的:

#if DEBUG
static NSString *const API_KEY = @"KEY_A";
#else
static NSString *const API_KEY = @"KEY_B";
#endif
Run Code Online (Sandbox Code Playgroud)

然后...

[Analytics startSession:API_KEY];
Run Code Online (Sandbox Code Playgroud)

这是如何转换为Swift的,因为Swift编译器不再使用预处理器?

cle*_*bit 118

更新:Xcode 8现在自动支持,请参阅@ DanLoewenherz上面的回复.

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

#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif
Run Code Online (Sandbox Code Playgroud)

但是为了让它们被Swift拾取,你需要在目标的Build Settings中设置"Other Swift Flags":

  • 打开目标的构建设置
  • 搜索"其他快速标志"
  • 添加您要使用的宏,前面是-D标志

在此输入图像描述


Dan*_*erz 117

Xcode 8开始,Apple完全支持Swift预处理程序标志,因此不再需要在"其他Swift标志"中设置这些值.

新设置称为"活动编译条件",它为Swift等效的预处理程序标志提供顶级支持.你使用它的方式与"其他Swift标志"完全相同,除了不需要用"-D"前置值(所以它只是更清洁一点).

Xcode 8发行说明:

Active Compilation Conditions是一个新的构建设置,用于将条件编译标志传递给Swift编译器.此设置的值的每个元素都传递给以-D 为前缀的swiftc ,其方式与Preprocessor Macros传递给clang的元素具有相同的前缀相同.(22457329)

在此输入图像描述

您使用上面的设置如下:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Run Code Online (Sandbox Code Playgroud)

  • 这是一个有用的答案,但是来自Objective-C的背景(正如我想象的许多iOS开发人员一样),我认为我需要指定“ = 1” ...我花了一些时间试图找出原因我当时没工作。所以,我想我会分享这个秘诀来帮助下一位。:]无论如何,谢谢您的回答! (6认同)
  • 注意:您应该**不**指定 =1 或任何其他 = 值。相反,您只需要指定标志名称。:] (2认同)
  • @JRG-Developer,@Dan Loewenherz 我在“活动编译条件”中设置了“DEBUG”,在“预处理器宏”中设置了“DEBUG=1”,但这个配置根本不起作用。我应该删除`DEBUG=1`吗??从上面的评论中不清楚。 (2认同)
  • @DanLoewenherz 你说得对。我在目标设置中为存档配置设置了“DEBUG”,因此每次运行 Debug 语句时都不会运行发布条件。任何遇到问题的人请先检查目标的“构建配置”。查看此答案 /sf/ask/634417031/#38987783 了解更多信息。 (2认同)

gar*_*jon 11

在 swift 包中,您必须在文件的swiftSettings参数内执行此操作。使用方法(Apple文档)Swift文档.targetPackage.swiftdefine

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

我的看起来像这样并且有效!

            swiftSettings: [
               .define("VAPOR")
            ]
Run Code Online (Sandbox Code Playgroud)

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

#if VAPOR
Run Code Online (Sandbox Code Playgroud)


Mic*_*nzo 5

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

  1. 将“秘密”放在封闭存储库中上面的纯文本文件中
  2. 创建一个../set_keys.sh包含列表的export API_KEY_A='<plaintext_key_aef94c5l6>'(使用单引号来防止评估)
  3. 添加一个运行脚本阶段,可以source ../set_keys.sh将其移动到执行顺序的顶部
  4. 在 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
Run Code Online (Sandbox Code Playgroud)