Library vs Framework in iOS

CocoaPods 终于支持了Swift,同时也发现Github团队的又一力作Carthage。它们都将包统一编译为Framework,但不同的是,Carthage 仅支持 iOS 8 & Xcode 6 Dynamic Framework 这一新特性。

Update 201504 CocoaPods 0.36 后也仅支持 Dynamic Framework,放弃了之前的 Static Framework 形式。

那这个编译结果有什么区别?

Static Library & Dynamic Library

这两者属于标准的编译器知识,所以讲的会比较多。

简单的说,静态链接库是指模块被编译合并到应用中,应用程序本身比较大,但不再需要依赖第三方库。运行多个含有该库的应用时,就会有多个该库的Copy在内存中,冗余。

动态库可以分开发布,在运行时查找并载入到内存,如果有通用的库,可以共用,节省空间和内存。同时库也可以直接单独升级,或作为插件发布。

Library & Framework

在iOS中,Library 仅能包含编译后的代码,即 .a 文件。

但一般来说,一个完整的模块不仅有代码,还可能包含.h 头文修的.nib 视图文件图片资源文件说明文档。(像 UMeng 提供的那些库,集成时,要把一堆的文件拖到Xcode中,配置起来真不是省心的事。)

Framework 作为 Cocoa/Cocoa Touch 中使用的一种资源打包方式,可以上述文件等集中打包在一起,方便开发者使用(就像Bundle),。

我们每天都要跟各种各样的Framework打交道。如Foundation.framework / UIKit.framework等,这些都是Cocoa Touch开发框架本身提供的,而且这些 Framework 都是动态库。

但Apple对待第三方开发者使用动态库的态度却是极端的否定,所以在iOS 7之前如果使用动态库是肯定会被reject的,reason。但在2014年Xcode6和iOS 8发布时却开放了这个禁地,应该主要是为了App Extension

Framework 包含什么?

到底Framework中有什么,这里来看Alamofire编译后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Alamofire.framework
├── Alamofire
├── Headers
│   ├── Alamofire-Swift.h
│   └── Alamofire.h
├── Info.plist
├── Modules
│   ├── Alamofire.swiftmodule
│   │   ├── arm.swiftdoc
│   │   ├── arm.swiftmodule
│   │   ├── arm64.swiftdoc
│   │   ├── arm64.swiftmodule
│   │   ├── i386.swiftdoc
│   │   ├── i386.swiftmodule
│   │   ├── x86_64.swiftdoc
│   │   └── x86_64.swiftmodule
│   └── module.modulemap
└── _CodeSignature
└── CodeResources

Framework 包括了二进制文件(可动态链接并且为每种处理器架构专属生成),这点和静态库并无区别,但不同的是,它包含其它资源:

  • 头文件 - 也包含Swift symbols所生成的头文件,如 Alamofire-Swift.h
  • 所有资源文件的签名 - Framework被嵌入应用前都会被重新签名。
  • 资源文件 - 像图片等文件。
  • Dynamic Frameworks and Libraries - 参见Umbrella Frameworks
  • Clang Module Map 和 Swift modules - 对应处理器架构所编译出的Module文件
  • Info.plist - 该文件中说明了作者,版本等信息。

Cocoa Touch Framework (实际内容为 Header + 动态链接库 + 资源文件)

Static Framework & Dynamic Framework

刚才也说明了Apple所创建的标准 Cocoa Touch Framework 里面包含的是动态链接库。而Dynamic Framework 为 Xcode 6中引入的新特性,仅支持 iOS 8,因为Carthage使用的是该特性,所以仅支持iOS 8,说明上有提。

但新版CocoaPods中使用Framework是能够支持iOS 7的,这说明它不是Dynamic Framework。推断它仅是将Static Library封装入了Framework。还是静态库,伪Framework。(v 0.36 正式版开始,仅提供 Dynamic Framework 的方式,不再支持 iOS7)。

关于Static Framework,见:

伪Framework 是指使用Xcode的Bundle来实现的。在使用时和Cocoa Touch Framework没有区别。但通过Framework,可以或者其中包含的资源文件(Image, Plist, Nib)。

Swift 与 Framework 的关系

在Xcode 6.0 Beta 4的 Release Notes 中,可以找到这句话:

1
Xcode does not support building static libraries that include Swift code. (17181019)

在静态库中使用Swift语言开发,在build时会得到:

1
2
3
error: /Applications/Xcode.app/Contents/Developer/Toolchains/
XcodeDefault.xctoolchain/usr/bin/libtool:
unknown option character `X' in: -Xlinker

CocoaPods 将第三方都编译为Static Library。这导致Pod不支持Swift语言。所以新版Pod已将Static Library改为Framework。

Pods 0.36.0.beta.1 虽然已经支持Swift,但在编译时仍会给出下面警告:

1
ld: warning: embedded dylibs/frameworks only run on iOS 8 or later

CocoaPods 0.36 rc 开始对Swift正式放弃旧的打包方式,使用Dynamic Framework,也就意味着不再支持 iOS 7。更多见:SO

其它扩展阅读:

Dynamic Framework

使用Dynamic 的优势:

  • 模块化,相对于Static Library,Framework可以将模块中的函数代码外的资源文件打包在一起。
  • 共享可执行文件 iOS 有沙箱机制,不能跨App间共享共态库,但Apple开放了App Extension,可以在App和Extension间共间动态库(这也许是Apple开放动态链接库的唯一原因了)。

iOS 8 Support only:

如果使用了动态链接库,在尝试编译到iOS 7设备上时,会出现在下错误:

1
2
3
ld: warning: directory not found for option '-F/Volumes/Mactop BD/repos/SwiftWeather/Carthage.build/iOS'
ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later (@rpath/Alamofire.framework/Alamofire) for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

REF::