iOS的动态库和静态库的差异区别以及静态库的好处
iOS的动态库和静态库的差异区别
好的,这是一个非常核心的iOS开发知识点。我们来详细、清晰地解析一下iOS中动态库和静态库的差异区别。
### 核心概念
* **库**:本质上是一个可执行代码的二进制集合,可以被其他程序调用。它封装了功能、资源,供开发者复用,避免重复造轮子。
* **静态库**:在**编译链接期**,被完整地复制到最终的可执行文件(.app)中。
* **动态库**:在**程序运行时**,由系统动态地加载到内存中。多个应用程序可以共享同一份动态库的实例。
---
### 详细对比表格
| 特性 | 静态库 | 动态库 |
| :--- | :--- | :--- |
| **文件格式** | `.a` 或 `.framework` (包含Headers的文件夹) | `.dylib` 或 `.framework` (包含Headers的文件夹) |
| **整合时机** | **编译时** | **运行时** |
| **整合方式** | 被完整地复制到最终的可执行文件中 | 不会被复制到可执行文件,只记录引用路径 |
| **App包体积** | **较大**(因为库的代码被内嵌) | **较小**(主程序体积小,但需要携带动态库) |
| **内存占用** | 可能**较高**(如果多个App使用同一静态库,各自内存中有一份副本) | **较低**(系统内存中只保留一份副本,供多个App共享) |
| **加载速度** | **启动稍快**(因为代码已在主程序二进制内,无需查找加载) | **首次加载稍慢**(需要查找和加载动态库) |
| **共享性** | **不可共享**(每个App都包含自己的副本) | **可以共享**(系统级动态库,如UIKit) |
| **热更新** | **不支持**(库代码已编译进App,上架后无法修改) | **原则上不支持**(AppStore审核禁止,但技术上可行) |
| **依赖管理** | 简单,所有代码都已包含,不存在依赖问题 | 需要确保目标设备上有正确的库版本,否则会崩溃 |
| **Apple的立场** | 对第三方开发者**推荐使用** | 对第三方开发者**限制使用**(只能使用系统提供的) |
---
### 深入解析与iOS特性
#### 1. 静态库
* **工作原理**:
1. 你在编译你的App时,链接器(Linker)会找到你引用的静态库(.a或.framework)。
2. 它将你的目标文件(.o)和静态库中**被用到的代码**一起打包,生成一个单一的、庞大的可执行文件。
3. 最终你的`.app`文件中,这个可执行文件已经包含了所有静态库的代码。
* **优点**:
* **部署简单**:App是一个自包含的整体,不存在运行时找不到库的依赖问题。
* **性能**:启动时略快,因为减少了动态链接的过程。
* **隐私和安全**:代码被内嵌,更难被单独逆向。
* **缺点**:
* **App体积增大**:如果多个App使用同一个静态库,那么每个App内部都有一份相同的代码,占用用户磁盘空间。
* **更新困难**:如果库需要修复Bug或更新功能,你必须重新编译整个App并发布新版本给用户更新。
#### 2. 动态库
* **工作原理**:
1. 编译时,链接器只记录下你使用了哪个动态库(比如 `libSystem.dylib`),以及所需的符号(函数、变量名)。
2. 生成的App可执行文件**并不包含**动态库的代码。
3. 当App启动时,系统的动态链接器(`dyld`)会根据记录的信息,去指定的路径(如系统目录 `/usr/lib`)查找并加载所需的动态库到内存中。
4. 如果多个App使用同一个系统动态库,它们会共享内存中已加载的那一份。
* **iOS对动态库的限制(非常重要!)**:
* **App Store审查规定**:第三方开发者**不允许**在自己的App中嵌入并使用自定义的动态库(`.dylib` 或自定义的 `.framework`)。这是因为动态库的加载机制可能被用来执行热更新或下载代码,这违反了App Store的安全和隐私准则。
* **唯一例外:App Extensions**
当你开发一个 **App Extension**(如Today Widget、Share Extension等)时,你的主App和Extension之间**可以且推荐**通过创建一个**自定义的动态 `.framework`** 来共享代码。这是因为主App和Extension属于同一个App Group,它们运行在同一个沙盒容器内,共享动态库是安全的,并且能有效减少整体安装体积。
* **系统动态库**:
* iOS系统中的所有基础框架,如 `UIKit`, `Foundation`, `CoreGraphics` 等,都是以动态库的形式提供的。这就是为什么你的App体积不会因为使用了庞大的UIKit而变得巨大的原因。
---
### 如何区分 `.framework` 是静态还是动态?
`.framework` 只是一个文件夹结构(Bundle),它既可以包裹静态库,也可以包裹动态库。
* **查看文件类型**:
在终端中,进入 `.framework` 文件夹,使用 `file` 命令查看同名文件(真正的二进制文件)。
```bash
# 查看一个 .framework 是静态还是动态
cd MyFramework.framework
file MyFramework
```
* **静态库输出**:`current ar archive random library`
* 这表示它是一个归档文件(`ar`命令打包的 `.o` 文件集合)。
* **动态库输出**:`Mach-O dynamically linked shared library`
* 这明确指出了它是一个动态链接的共享库。
* **在Xcode中查看**:
在Target的 **"General" -> "Frameworks, Libraries, and Embedded Content"** 部分,系统提供的动态库会标记为 **"Do Not Embed"**,而你自己创建的动态库需要标记为 **"Embed & Sign"**。静态库则通常不需要嵌入这一步。
---
### 总结与选择建议
* **对于第三方iOS开发者**:
* **制作给别人用的库**:你**只能**提供**静态库**(`.a` 或静态的 `.framework`)。
* **在自己的多个App间共享代码**:使用**静态库**,或者通过源码依赖(如CocoaPods、Swift Package Manager)。
* **在主App和App Extension间共享代码**:这是唯一推荐使用**自定义动态库**(动态的 `.framework`)的场景。
* **对于Apple**:
* 它提供所有的系统框架作为**动态库**,以实现最佳的资源利用和共享。
简单来说,在iOS生态中,由于沙盒和安全限制,**“静态库是常态,动态库是特例”**。这个特例仅限于系统框架和App与其Extension之间的代码共享。
广告SDK用静态库的好处