[译]Xcode 环境配置最佳实践

前言

工欲善其事,必先利其器。在 iOS 中,如何处理 配置环境 和根据需求自定义的 设置 关系也尤其重要。虽然 Xcode 提供了一系列的工具帮助咱们进行妥善地配置。但遗憾的是,我见过的不少团队在绝大多数时候都没有充分利用这些辅助工具。这并非他们的错:苹果只为咱们提供了一些不怎么好用的默认配置,而没有更好的帮助咱们学习如何达到最佳实践。前端

在这篇文章里,咱们将探索如何更好地利用 Xcode 配置,如何把 APP 的设置定义得更加有条理。android

Xcode 配置

Xcode 能够经过各类配置构建不一样设置的包。通俗地讲,配置就是告诉编译器如何构建版本的一系列设置。IDE 容许你根据不一样的配置来自定义一些设置。你可能常常看到这些:ios

等等…git

Debug vs. Release

Debug 和 Release 是 Xcode 提供的两种默认配置。你彻底也能够建立你本身的配置,但咱们一般不这么作,由于自定义的配置是否有效可能取决于项目,iOS 开发者们对哪些配置能够对项目广泛有效尚未达成共识。github

这两种默认配置有几处差异,具体的差异在这里我不会详细讨论,只是简单归纳下:swift

debug 构建的版本中,Xcode 会给咱们发送完整的符号调试信息来帮助咱们调试应用,而且 Xcode 不会对代码进行优化(更快的构建速度)。而在 release 构建的版本中,不会发送调试信息而且代码会被优化(较慢的构建速度)。后端

至于这两种配置的用途,debug 一般会在咱们平常开发中使用。而 release 咱们一般会在须要将 APP 分发给其余非开发人员如:测试人员、项目经理、客户或用户时使用。api

须要注意的是,这两个配置一般是不能彻底知足需求的。并且开发者常常把 ≪debug vs. release≫ 和 ≪staging vs. production≫ 这两个概念搞混,这彻底是不该该的。xcode

咱们能够继续完善

一些项目使用不一样的配置环境:开发环境、临时环境、生产环境、预生产环境等等,用你最想用的那个就好。这种分类方式和上面讨论的两种默认配置没有直接联系。就算咱们强制这么分类,用的时候达到的效果也没有想象中的那样好。好比,你想准备构建一个 release 版本,但这并不意味着你的 APP 必定要指向 生产 服务器:想像一下,你须要为 QA 打个 release 的版本的包,而这个包须要在临时服务器上进行测试。 这时就连 debug & release 两个默认的配置也不能知足需求了。bash

所以,我想用能够知足咱们更多需求的其余配置方案来代替基本的 debug & release 配置。为了足够简单,在个人方案中只会保留临时环境和生产环境,在你须要使用其它环境配置时,你会发如今个人方案里能够轻松添加。

让咱们从新定义配置环境

咱们能够定义四种配置环境:

  • Debug Staging
  • Debug Production
  • TestFlight Staging
  • TestFlight Production

从它们的名字上,你就能猜到它们大概的设置,下面就是它们的详细设置:

  • 前两个(Debug Staging & Debug Production)和默认的 Debug 配置同样,但 每一个都指向不一样的服务器环境
  • 后两个配置环境(两个 TestFlight 配置环境 )也是这样,它们和默认的 Release 配置同样,不包含调试信息并进行了代码优化,但 每一个都在对应的服务器环境下使用

实现的操做也是很是简单,找到 project 的 Settings > Info > Configurations,而后点击 + 按钮。拷贝一份 Debug 配置,并将默认的配置命名为 “Debug Staging”,拷贝出来的配置命名为 “Debug Production”。按照这个方式对 Release 进行处理。

当你操做完后是这个效果:

一个 project 包含四种不一样的配置环境。

第五种配置环境

我使用 “ TestFlight” 命名 release 配置,而不是使用原来的 “Release” 命名是有缘由的。由于代码中有些特定事件只在最终用户使用时触发,而在测试人员和客户使用时不触发。一个具体的场景就是使用用户统计来跟踪事件,这可能要求跟踪事件仅做用于最终用户,而不是生产环境下的测试人员。在这种状况下, 咱们就要考虑 TestFlight Production 配置具备的细微差异,所以咱们须要将这个配置继续细分下去。引进第五种配置:

  • AppStore

你能够快速地拷贝一份 TestFlight Production 来添加这个配置。但须要注意的是这个配置可能一直不会用到,由于你不必定会遇到须要细分 TestFlight Production 配置的需求。

那么,如今你可能很想知道 如何根据所选配置来管理 APP 中的触发事件。这些将会在接下来部分详细介绍。

自定义设置

有不少方式能够作到根据所选不一样配置来执行不一样的操做:预编译器指令、环境变量、各类 plist 文件等等。这些方式都有本身的优缺点,这里只讨论我将采起的比较纯净的方式。

须要根据配置执行的各类操做一般能够由变量来控制,经过这些变量来决定 APP 的行为。这些变量一般称为 settings 。好比一些像这样的 settings :服务器 API 的 base URL、Facebook App ID、日志的详细级别、是否支持离线访问等等。

接着,展现我如今如何根据所选配置来管理这些自定义 settings 的方法。从个人以往经验来看,这是目前最方便的方案。

Settings.swift

APP 的自定义 settings 能够经过单例很简单的获取到。

struct Settings {
    static var shared = Settings()
    let apiURL: URL
    let isOfflineAccessEnabled: Bool
    let feedItemsPerPage: Int
    private init() {
        let path = Bundle.main.path(forResource: "Info", ofType: "plist")!
        let plist = NSDictionary(contentsOfFile: path) as! [AnyHashable: Any]
        let settings = plist["AppSetings"] as! [AnyHashable: Any]
        
        apiURL = URL(string: (settings["ServerBaseURL"] as! String))!
        isOfflineAccessEnabled = settings["EnableOfflineAccess"] as! Bool
        feedItemsPerPage = settings["FeedItemsPerPage"] as! Int
        
        print("Settings loaded: \(self)")
    }
}
复制代码

这个结构体用来读取和记录 APP 的各类 settings(这些 settings 会在 APP 的 Info.plist 文件中定义),这样咱们就能够在代码中随时拿到这些 settings。在这里我喜欢使用强制解包,由于这样若是缺乏某项设置,APP 也会没法运行。

Info.plist

Info.plist 文件中定义 appSettings 。这里我建议你们使用字典把这些设置汇总到一块儿。

这样,咱们就很是纯净地完成了对 APP settings 的读取。这些 settings 在不一样的配置环境中值都是不一样的,还差一点就完成了。

User-Defined Settings

想一下,在全部的工程内 什么会随配置的不一样而改变 ? 对,编译器的代码优化级别、header 的搜索路径、描述文件等等。若是咱们可以定义咱们本身的随所选配置改变的设置,那不就简单了!事实证实,咱们确实能够建立用户自定义的设置。

建立 User-Defined settings 很是简单,只须要在你的 Target > Build Settings 中,点击 + 按钮,而后选择 “Create User-Defined Setting”。这些也能够在 project > Build Settings 下建立,但我以为在 Target > Build Settings 建立更合适。

由于你刚建立的 User-Defined Settings 可能还需与其余的 Settings 来搭配使用,因此建议最好用合适的前缀来命名。

我这里使用了我名字缩写来做为 User-Defined Settings 的前缀, 但我建议最好用项目名的缩写。

接下来,在你的 Info.plist 文件中引用对应的属性值,你能够这样作:

$(YOUR_USER_DEFINED_SETTING_NAME)
复制代码

整合所有

真正神奇的地方在于:你能够将 Info.plist 中 settings 的全部已经填好的属性值替换为 User-Defined Setting 的对应地址。而你现有的自定义 setting 各需对应一条 User-Defined Setting。

Info.plist 文件被编译时,它会获取所选配置对应的全部 settings 属性值,而这些属性值也会在编译时对应到每一个 settings 上。

如今,你就能够在你的代码里随时随地 优雅 地获取到这些 settings 的属性值:

if Settings.shared.isOfflineAccessEnabled {
    // do stuff
}
复制代码

最后,在 Xcode 中选择所需的编译配置就很是简单了:

或者在 CLI 中:

总结

采用这套方案,咱们会得到这些好处:

  • 有组织地构建工做流程。
  • 有组织地管理应用程序的自定义设置。
  • 根据配置灵活改变设置。
  • 轻松持续集成(在命令行工具中,选择要编译的配置很容易实现)。

然而,这个方案也有些值得警戒的地方:

  • 在运行时不能灵活地更改设置,由于设置在编译时就被打包到版本内了。
  • 在配置之间切换时体验并非很好:每次更改配置后,Xcode 都会从新建立一个版本,也就是说你必须等待整个项目从新编译。
  • 只能在 .xcodeproj 中修改这些设置的值,而不能在外部 灵活 修改这些设置的值。
  • User-Defined Settings 暴露给了全部可以接触到代码的人 , 因此千万不要把任何重要的 key 值放到这里

虽然这些隐患能够一一排除,可是,这个方案的初衷只是为了从这片几乎空白的领域摸索出这些工具更好的使用方法。解决这些问题就意味着更多更复杂的修改,并且这些已经超出了本文讨论的内容,我不但愿这篇文章跑题。但相信我,咱们作的已经足够完善了。在下篇文章里,咱们将研究如何处理这些隐患,并让咱们的项目变得更加完善...

待续。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索