細說iOS靜態庫和動態庫


iOS中的靜態庫和動態庫

靜態庫

  • 靜態庫完全復制進可執行的二進制里面
  • 后綴是.a或者.framework

動態庫

  • 動態庫是在程序冷啟動時候被鏈接到手機內存或者 App 內存里面
  • 后綴是.tbd或者.framework

關於說明很多,可以看一下網上的文章。我現在說的是基於上面理論的證明。剛開始覺得網上說的可能不太准確,后來得到驗證是正確的。

為了研究我們創建的.a.framework到底是靜態庫和動態庫,我們分別創建對應的簡單的庫。

我們分別可以通過上面圖中紅色區域創建.framework.a。我們知道區分是靜態庫還是動態庫最終是我們選擇的 Mach-O 的類型到底是Dynamic Library還是Static Library

Mach-O 類型

這里簡單說一下Mach-O類型,為什么說簡單說一下。因為深入我也不了解了,深入可以谷歌資料。

  • Executable:應用的主要二進制

  • Dylib Library:動態鏈接庫(又稱DSO或DLL)

  • Static Library:靜態鏈接庫

  • Bundle:不能被鏈接的Dylib,只能在運行時使用dlopen( )加載,可當做macOS的插件

  • Relocatable Object File:可重定向文件類型

靜態庫和動態庫的對比

為了讓打出來的庫更加的真實,我們使用網上出名的庫作為測試。我們選取的是FLEX作為測試的目標,因為這個庫所包含的文件多,數據真實性更加的可靠。我們編譯的環境是基於iPhone 6s Plus進行編譯出來的,真正的大小會包含其他框架會比我測試大得多。

二進制大小

二進制大小(iPhone 6s Plus) .a .framework
靜態庫 6.8MB 4.6MB
動態庫 1.6MB 1.6MB

為了驗證我們所謂靜態庫和動態庫是否是真正的靜態庫和動態庫,我們使用File命令和Mach-O查看軟件分別對比一下。

File 命令

輸出顯示 .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)

Mach-O 查看

輸出顯示 .a .framework
靜態庫 ✅(Static Library) ✅(Static Library)
動態庫 ✅(Shared Library) ✅(Shared Library)

我們對比結果發現,不管是.a還是.framework都可以作為動態鏈接庫來使用,這和我們在網上看到文章說.a是靜態庫是不嚴謹的。

作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS交流群:519832104 不管你是小白還是大牛歡迎入駐,分享經驗,討論技術,大家一起交流學習成長!

另附上一份各好友收集的大廠面試題,需要iOS開發學習資料、面試真題,可以添加iOS開發進階交流群,進群可自行下載!

我們按照靜態庫是完整被拷貝到工程二進制里面,動態庫是在啟動時候動態鏈接的描述,我們分別對比一下運行包里面的表現。我們同樣是按照iPhone 11 Pro Max做為對比的,這樣數據比較真實。

靜態庫和動態庫在包里面的表現

Static Library.a.framework

代碼所在的位置
代碼所在位置(iPhone 6s Plus) .a .framework
靜態庫 App 二進制中 App 二進制和 Frameworks 文件夾中
動態庫 無(二進制沒有 Frameworks文件夾 沒有) Frameworks 文件夾中
App 二進制大小對比
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

XCFrameworks

XCFrameworks 和之前 Framework 對比

說完了我們常用的動態庫和靜態庫,我們說一下今年出的新特征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 和頭文件

我們事先准備好模擬器和真機架構的.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

包含第多個不同的Framework(不支持)

假設我們的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

點擊此處,立即與iOS大牛交流學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM