对于讲解iOS
中静态库和动态库的文章已经不少了,以前本身也总结了一篇。从今天目前来讲,以前就是总结了皮毛。今天的文章也算是后续的总结,应该随着后面的深刻还会有不一样的体会。ios
- 静态库彻底复制进可执行的二进制里面
- 后缀是
.a
或者.framework
- 动态库是在程序冷启动时候被连接到手机内存或者 App 内存里面
- 后缀是
.tbd
或者.framework
关于说明不少,能够看一下网上的文章。我如今说的是基于上面理论的证实。刚开始以为网上说的可能不太准确,后来获得验证是正确的。git
为了研究咱们建立的.a
和.framework
究竟是静态库和动态库,咱们分别建立对应的简单的库。github
咱们分别能够经过上面图中红色区域建立.framework
和.a
。咱们知道区分是静态库仍是动态库最终是咱们选择的 Mach-O
的类型究竟是Dynamic Library
仍是Static Library
。xcode
这里简单说一下Mach-O
类型,为何说简单说一下。由于深刻我也不了解了,深刻能够谷歌资料。bash
Executable:应用的主要二进制架构
Dylib Library:动态连接库(又称DSO或DLL)mvc
Static Library:静态连接库框架
Bundle:不能被连接的Dylib,只能在运行时使用dlopen( )加载,可当作macOS的插件iphone
Relocatable Object File:可重定向文件类型post
上面的解释也是抄别人的(小声).
为了让打出来的库更加的真实,咱们使用网上出名的库做为测试。咱们选取的是FLEX做为测试的目标,由于这个库所包含的文件多,数据真实性更加的可靠。咱们编译的环境是基于iPhone 6s Plus
进行编译出来的,真正的大小会包含其余框架会比我测试大得多。
二进制大小(iPhone 6s Plus) | .a | .framework |
---|---|---|
静态库 | 6.8MB | 4.6MB |
动态库 | 1.6MB | 1.6MB |
为了验证咱们所谓静态库和动态库是不是真正的静态库和动态库,咱们使用File
命令和Mach-O查看软件分别对比一下。
输出显示 | .a | .framework |
---|---|---|
静态库 | ✅(current ar archive) | ✅(current ar archive) |
动态库 | ✅(Mach-O 64-bit dynamically linked shared library x86_64) | ✅(Mach-O 64-bit dynamically linked shared library x86_64) |
输出显示 | .a | .framework |
---|---|---|
静态库 | ✅(Static Library) | ✅(Static Library) |
动态库 | ✅(Shared Library) | ✅(Shared Library) |
咱们对比结果发现,不论是.a
仍是.framework
均可以做为动态连接库来使用,这和咱们在网上看到文章说.a
是静态库是不严谨的。
咱们按照静态库是完整被拷贝到工程二进制里面,动态库是在启动时候动态连接的描述,咱们分别对比一下运行包里面的表现。咱们一样是按照iPhone 11 Pro Max
作为对比的,这样数据比较真实。
Static Library
的.a
和.framework
代码所在位置(iPhone 6s Plus) | .a | .framework |
---|---|---|
静态库 | App 二进制中 | App 二进制和 Frameworks 文件夹中 |
动态库 | 无(二进制没有 Frameworks文件夹 没有) | Frameworks 文件夹中 |
App二进制大小(iPhone 6s Plus) | .a | .framework |
---|---|---|
静态库 | 93KB | 93KB |
动态库 | 92KB | 92KB |
冷启动速度(iPhone 6s Plus) | .a | .framework |
---|---|---|
静态库 | 151.44毫秒 | 53.35毫秒 |
动态库 | 0 毫秒(运行报错) | 254.58毫秒 |
热启动速度 | .a | .framework |
---|---|---|
静态库 | 160.99 毫秒 | 154.65 毫秒 |
动态库 | 0 毫秒(运行报错) | 199.04 毫秒 |
这里描述的冷启动是指代程序第一次安装以后运行可能会加载系统动态库而形成启动时间边长,热启动是第二次启动不须要加载系统动态库。
经过上面的代码位置,二进制大小,冷启动速度和热启动速度大概能够得出一个结论。虽然严格来讲.a
是支持打包出来动态库的,可是代码不会复制进二进制,也不会存放在Frameworks
里面。形成咱们打出来的动态库.a
在程序里面没法运行,也就换句话说.a
只支持静态库特征了。
虽然.a
的静态库的热启动比冷启动还要慢,可是这几毫秒的偏差能够抛弃。可能基于咱们手机已经打开了其余应用形成冷启动没有再次加载系统动态库而和热启动速度差很少。
可是对比.framework
能够得知静态库
的启动速度确实比动态库
的加载速度快不少。而静态库的.framework
会存在两份,因此安装包会变大,由于静态库的.framework
直接复制进二进制里面,因此二进制会变大。
经过上面咱们得出下面的结论
.a
只支持静态库(打包出动态库也是支持的 只不过目前 iOS 不支持加载).framework
静态库会存在于二进制和Frameworks
两份。.framework
比.a
的二进制文件小的多.framework
不推荐用.a
说完了咱们经常使用的动态库和静态库,咱们说一下今年出的新特征XCFramework
。根据以前一篇文章了解,XCFramework
是为了取代以前的.framework
的。
我很想深刻的探究一下XCframeworks
来谈一下用这个的好处,可是苹果对于这个的资料少之又少。咱们经过真实的对比一下XCFrameworks
的好处。
咱们经过对比包含模拟器
和真机
的.framework
和对比.xcframework
对比一下数据。
对于生成多架构的.framework
咱们须要用到lipo
命令进行合成,可是对于生成.xcframework
能够用到个人xcbuild
的脚本生成。
(X86_64 + ARM64) | .framework | .xcframework |
---|---|---|
文件大小 | 10.6MB | 10.8MB |
二进制大小 | 10.4MB | 8.3MB+2.2MB |
App 大小(iPhone 6S Plus Debug) | 4.8MB | 2.8MB |
冷启动 | 169.8 毫秒 | 155.52毫秒 |
热启动 | 159.56 毫秒 | 153.62 毫秒 |
经过对比.xcframework
比.framework
不但 App 大小少了不少,并且还对于启动速度提高了很多。
咱们以前说的能够将.a
和头文件打包到.xcframework
中,咱们下面尝试一下。
咱们事先准备好模拟器和真机架构的.a
和头文件,使用下面的命令建立一个XCFrameworks
.
xcodebuild -create-xcframework -library <path> [-headers <path>] [-library <path> [-headers <path>]...] -output <path>
//Example
xcodebuild -create-xcframework -library /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphonesimulator/libMyLibrary.a -headers /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphonesimulator/include/MyLibrary -library /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphoneos/libMyLibrary.a -headers /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/Debug-iphoneos/include/MyLibrary -output /Users/zhangxing/Library/Developer/Xcode/DerivedData/MyLibrary-frqlmvciureprnbnytogqzjagose/Build/Products/MyLibrary.xcframework
复制代码
假设咱们的MyFramework
依赖一个咱们本身的另外的库或者其余第三方的库
xcodebuild -create-xcframework -framework <path> [-framework <path>...] -output <path>
//Example
xcodebuild -create-xcframework -framework /Users/zhangxing/Downloads/data/MyFrameworkB.xcframework/ios-arm64/MyFrameworkB.framework -framework /Users/zhangxing/Downloads/data/MyFrameworkB.xcframework/ios-x86_64-simulator/MyFrameworkB.framework -framework /Users/zhangxing/Downloads/data/ios-arm64/MyFramework.framework -framework /Users/zhangxing/Downloads/data/ios-x86_64-simulator/MyFramework.framework -output /Users/zhangxing/Downloads/data/MyFrameworkC.xcframework
复制代码
结果是一个 XCFrameworks
只能包含一个框架,可是能够包含多个架构。和以前写的文章写的理解有误,这里纠正一下。
Fat Framework
变成最新的XCFramework
若是有源码能够直接使用xcbuild
命令生成,若是没有或者是其余第三方的可使用下面的命令。
lipo 静态库源文件路径 -thin CPU架构名称 -output 拆分后文件存放路径
复制代码
用分离出来的架构从新合成XCFrmaework
。
其实这样很麻烦,以后我会有空完善一下xcbuild
的功能。写到这里这篇文章就写完了,对于静态库和动态库知道了一些,还有一些疑惑。对于XCFrmaework
验证了一些猜测,也存在太多的疑问。