CocoaPods 0.36 - 框架和 Swift 支持

TL;DR:CocoaPods 0.36 已发布,并附带期待已久的对框架和 Swift 的支持。

CocoaPods 0.36 添加了对动态框架的支持,并由此也增强了对使用 Apple 新编程语言 Swift 的依赖的支持。这是 CocoaPods 中最大的单一变更之一,影响了 CocoaPods 的几乎所有子系统,例如 Xcodeproj

iOS 上还有 Swift 和动态框架

动态框架一直可在 OS X 上使用。iOS 则不同。Apple 的移动平台在 iOS 8 中引入了第三方动态框架支持。因此,使用静态库找到了最小公分母,静态库一直受这两个平台支持。

在 iOS 上引入动态框架的同时,Apple 还引入了 Swift。如果你有 Swift 中的第三方依赖,你只有两个选择:将它们放入你的项目并编译一个 fat 二进制文件,这不是一个实用的解决方案,因为它增加了构建时间,限制了增量编译的可用性,并且难以通用地管理非常不同的依赖,这些依赖可能需要不同的构建设置等。或者,你可以使用框架。静态库不再是一种选择。

为什么是这样?因为 Apple 不允许你构建包含 Swift 的静态库。与 Objective-C 不同,Apple 不会将 Swift 标准运行时库与 iOS 一起发布。这将语言版本与平台版本分离。当你使用 Swift 构建应用时,你负责自己发布它们。默认情况下,Xcode 使用 swift-stdlib-tool 来处理复制 Swift 运行时 dylib,但当尝试发布使用 Swift 的框架时,该工具无法满足仅使用 Objective-C 的应用的需求。你的应用可执行文件和你发布的框架都将使用同一组 dylib,这些 dylib 嵌入到应用程序包的 Frameworks 子目录中。首先,这是因为你无法链接到不同版本的标准库。此外,由于与内存大小和网络速度相关的限制(与分发相关),最好只嵌入它们一次,而不是多次。

在此版本中,我们最初允许您将两者与 CocoaPods 结合使用。您可以通过指定 use_frameworks! 来让 CocoaPods 通过框架而不是静态库集成到您的项目中。如果不存在该指定,则您将无法集成依赖项,如果您依赖于包含 Swift 源代码的 pod。这是每个集成目标的全部或无策略,因为我们无法确保正确构建框架,其传递依赖项是静态库。此版本伴随着整个项目可能最彻底的更改之一,其中包括 CocoaPods 本身,但也需要对 Xcodeproj 进行类似的更改。

动态框架与静态库

那么这两种产品类型之间有什么区别呢?

一个区别在其名称中很明显:动态和静态是相反的。这解释了在集成时它们如何链接到您的代码。静态库只是您已编译源代码的存档,可以部分集成。在它们链接到其他位置之前,它们不会链接到自身。动态库是最终链接的可执行文件。在构建它们时,它们会被链接,并且链接器会对它们的依赖项以及预期它们所在的位置进行编码。一旦它们被构建,二进制文件本身就不会再被更改。

另一个区别是它们的文件系统表示:框架是捆绑包,这基本上意味着它们是具有文件后缀 .framework 的目录,并且 Finder 主要将它们视为常规文件。而库只是单个 FAT 二进制文件,不能携带任何资源作为不同的文件。如果您点击框架,您将看到一个常见的目录结构

除了二进制文件之外,它们还捆绑了一些进一步的数据,在这种情况下,这些数据可以动态链接并为每个架构保存不同的切片。但这只是静态库迄今为止涵盖的一部分。在进一步的数据中,有以下内容

  • 公共头文件 - 这些头文件针对应用程序目标进行了剥离,因为它们对于将框架分发为编译代码非常重要。公共头文件还包括为公共 Swift 符号生成的标头,例如 BananaKit-Swift.h
  • 整个内容的代码签名 - 在将框架嵌入到应用程序目标中时,必须重新计算此项,因为标头之前已被剥离。
  • 其资源 - 用于 UI 组件的资源,例如图像。
  • 托管动态框架和库 - 这可能是 Apple 提供的所谓伞形框架的情况。在 CocoaPods 中,没有这种情况发生时的用例。
  • Clang 模块映射 - 这主要是一个内部工具链工件,其中包含有关标头可见性和模块可链接性的声明。
  • Info.plist - 这指定了作者、版本和版权信息。

注意事项

关于捆绑资源的一个注意事项是,到目前为止,我们必须将所有资源嵌入到应用程序包中。资源通过 [NSBundle mainBundle] 以编程方式引用。Pod 作者可以使用 mainBundle 引用来包含 Pod 带入应用程序包的资源。但是对于框架,您必须确保通过获取对框架包的引用来更具体地引用它们,例如

[NSBundle bundleForClass:<#ClassFromPodspec#>]
NSBundle(forClass: <#ClassFromPodspec#>)

这将适用于框架和静态库。只有在非常罕见的情况下,您才希望直接或间接地引用主包,例如通过使用 [UIImage imageNamed:]

改进的资源处理的优点是,当资源具有相同名称时,它们不会冲突。它们由框架包命名。此外,我们不必将构建规则应用到资源上,因为例如资产目录和情节提要需要编译。这应该会减少使用包含许多资源的 Pod 的项目的构建时间。

@IBDesignable - 框架的另一个原因

Xcode 6 允许您在 Interface Builder 中预览您自己的自定义视图组件。要使用该功能,视图组件必须存在于其自己的框架中。

关于框架的更多信息

如果您想了解有关框架的更多信息,请查看 框架编程指南。尽管这不是专门为新的 Cocoa Touch 框架编写的,但 Apple 在 Xcode 目标模板中如何称呼它们,它们与经典 OS X 框架基本相同,因此本文档仍然是有用的介绍。

私有 Pod 和 source

最后一点,此版本中的另一个更改涉及私有规范存储库。

在 CocoaPods 0.36 及更高版本中,当使用来自私有规范存储库的 pod 时,你需要明确列出所有使用的规范存储库,方法是在 Podfile 中使用 source 指令。

这对于确保团队中的每个人都使用相同规范引用(无论其本地配置如何)非常重要。

请注意,如果你不使用私有 pod(并且只使用来自官方规范存储库的 pod),则无需列出任何 source,因为这将默认仅使用 CocoaPods/Specs

更新

要安装 CocoaPods 的最新版本,你可以运行

$ [sudo] gem install cocoapods

在版本 1.0 之前,我们强烈建议你保持 CocoaPods 为最新状态。

有关所有详细信息,请不要错过变更日志