04-iOS架構設計|iOS開發包二進位制化【.a靜態庫、,.framework(靜態庫、動態庫)、.dyld動態庫、XCFameworks等】
前言
我們之前通過一篇文章在討論“移動客戶端架構設計
的時候,僅是通過一篇文章進行了綜述。\
後來,我就換工作,來到了Nike。近半年一直很忙,最近接到一個工單,要求升級SDK。藉此契機,簡單回顧一下iOS開發包二進位制化,並進一步認識一下我們比較陌生的 XCFramework
一、綜述
專案中庫的劃分:
- 我們在實際開發中,若是專案比較龐大,我們可以將 庫 劃分為:
私有庫:
(若是我們的公司移動開發建設比較成熟,也可以理解為我們內部移動開發套件的私有庫)
二方庫
: 因專案建設需要而採購的,由 服務 供應商 提供的SDK庫。如:埋點服務SDK、阿里的反爬蟲服務SDK、OCR掃描服務等。(通常需要付費 或 有限 免費體驗 SDK功能)
三方庫
: 免費使用的外部庫(通常來源於Github等開源平臺)iOS開發中的庫的二進位制化處理(功能模組閉源處理)
- 根據是否將庫的功能服務實現程式碼開源,我們又可以將庫 劃分為 “
開源庫
”、“閉源庫
”
二進位制化
: 把功能服務模組的原始碼 打包成 【閉源庫】的開發,也就是iOS開發包二進位制化
處理!!!!(二進位制化處理也可以稱為SDK開發)
- 在iOS二進位制化開發中,可以將模組打包成
靜態庫
/動態庫
的形式
- 這些
靜態庫
、動態庫
,可以統稱為二進位制庫
;
- 二進位制化庫開發完畢後,我們可以把庫
整合
在一個專案裡面進行使用;
1. 二進位制化庫的幾種分類
在iOS開發中的二進位制化庫可以簡單劃分為,靜態庫、動態庫(.framework)(注:不是所有的.framework就一定是動態庫)
- 靜態庫: 以.a
或者 .framework
作為檔案的副檔名。連結時完整地拷貝至可執行檔案中,被多次使用就有多份冗餘拷貝
- 動態庫: 以.dylib
或者 .framework
作為檔案的副檔名。連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫,系統只加載一次,多個程式共用,節省記憶體。注意
:
- 動態庫只能蘋果使用,如果專案中使用了動態庫不允許上架(如:jspatch)
- 我們在開發過程中,即使有用到系統動態庫的需求,也要常常檢查對動態庫的引入需要,因為這會影響App的啟動速度。(若是不太瞭解這一塊的朋友,可以通過我的這篇文章簡單瞭解一下:App啟動裝載的過程)
- .a
與.framework
的區別?
- - .a是一個純二進位制檔案,.framework中除了有二進位制檔案之外還有資原始檔;
- - .a檔案不能直接使用,至少要有.h檔案配合,.framework檔案可以直接使用。
- - .a + .h + sourceFile = .framework
- - 建議用.framework
2. 簡單瞭解CPU架構
我們在開發好功能服務模組,準備匯出二進位制化包的時候,我們要根據 自身投放應用市場的需要硬體設陪適配需要,對庫進行的CPU架構的支援。從而在滿足自身需要的同時,避免匯出二進位制化包的體積過大。
2.1 什麼是CPU架構?
CPU架構是CPU廠商給屬於同一系列的CPU產品定的一個規範,主要目的是為了區分不同型別CPU的重要標示。
目前市面上的CPU分類主要分有兩大陣營,一類是複雜指令集(CISC)CPU,另一類是精簡指令集(RISC)CPU。我們今天要討論的ARM指令集就屬於精簡指令集(RISC)CPU。
2.2 ARM處理器
ARM處理器是英國Acorn有限公司設計的低功耗成本的第一款RISC微處理器。全稱為Advanced RISC Machine。
我們之前有一篇文章是關於探究iOS底層原理|ARM64彙編的。其中簡單介紹了,不同的型號真機硬體裝置的CPU硬體架構:
| 架構 | 裝置 | | ------ | ---------------------------------------------------------------------------------------------------- | | armv6 | iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch | | armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 | | armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) | | arm64 | iPhone5S 以後 iPhoneX , iPad Air, iPad mini2以後 |
ARM處理器因其低功耗和尺寸小而聞名,iPhone的處理器全部都基於ARM。
我們經常見到的armv7 | armv7s | arm64都是ARM處理器的指令集。
指令集應用於開發有如下特點:
- 所有指令集原則上向下相容。
- Xcode的模擬器是執行在電腦上的,所以iPhone模擬器並沒有使用ARM指令集,而是使用的X86(64為處理器)或者i386(32位處理器)。
- 通過Xcode打包時,會為支援的所有的指令集編譯出對應的指令集程式碼的資料包,所以工程支援的指令集越多,生成的二進位制包就越大。
2.3 進一步認識 指令集 對應的機型
機型-架構 對照表
| 架構 | 裝置 | | ------ | ---------------------------------------------------------------------------------------------------- | | armv6 | iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch | | armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 | | armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) | | arm64 | iPhone 5S、iPhone 6、iPhone 6 Plus、iPhone 6S、iPhone 6S Plus、iPhone 7、 iPhone 7 Plus、 iPad (2018)、 iPhone 8 、 iPhone 8 Plus 、 and iPhone X | | arm64e| iPhone XS 、iPhone XS Max 、 iPhoneXR、iPhone 11 、 iPhone 11 Pro、 iPhone 11 Pro Max、iPhone 12 、 iPhone 12 Mini 、 iPhone 12 Pro 、 iPhone 12 Pro Max ... 等|
模擬器
- - 模擬器32位處理器測試需要i386架構 - - 模擬器64位處理器測試需要x86_64架構 - - 模擬器64位處理器測試需要arm64架構(蘋果M1系列之後的arm64而非真機的arm64
)
真機
- - 真機32位處理器需要armv7,或者armv7s架構 - - 真機64位處理器需要arm64架構
應對當前(2023年)市場常用的裝置推薦適配 指令集
- 模擬器: 64位處理器x86_64
架構、arm64
架構 - 真機:64位處理器arm64
架構、armv7s
架構(iPhone5及其以上的裝置)
2.4 二進位制化庫適配架構的設定Build Setting
Build Settings
中搜索Architecture
,可以看到如下圖的設定項:
- Architectures
指定當前Target
被編譯時支援的指令集的列表,如果指定了多個架構,機會生成多個架構需要的二進位制檔案。 - Build Active Architecture Only
指定是否只編譯當前連線裝置所支援的指令集。
預設Debug
時為YES
,Release
時為NO
。設定為YES
時,編譯後只生成當前連線裝置所支援的指令集程式碼,編譯速度更快。 - Excluded Architectures
指定當前Target
被編譯時拒絕接納的指令集列表,編譯後最終生成的二進位制檔案支援的指令集是Architectures
減去Excluded Architectures
。
二、開發二進位制化庫的實踐
我們前面有提及 靜態庫
、動態庫
,的區別。我們這裡就不再重複介紹。\
我們直接進入建立一個.framework靜態庫的實踐(此次我採用的是Xcode14.1,與之前的Xcode版本的建立過程總體上大致相似,略有不同。若是同學們用比較老的Xcode版本,請自行尋找相應教程)
1. 首先建立.frmawork
專案
在framewrok
中可以封裝入自己需要封裝的內容
eg: 我在Logger.h
中加入了一個測試方法
``` // // Logger.m // NKTestOCFramework // // Created by Van Zhang on 2023/2/27. //
import "Logger.h"
@implementation Logger
-
(void)logWithString:(NSString *)log{ NSLog(@"Log:%@",log); }
-
(NSString )testString:(NSString )string { return [@"NKTestOCFramework: " stringByAppendingString:string]; }
@end
```
2. 接下來進行專案配置:
1、設定Build Setting引數 將Build Active Architecture only
設定為NO
2、設定Build Setting引數 Mach-O Type
為Static Library (配置靜態、動態)
3、設定Build Setting引數 在Architectures
下增加 需要適配的硬體CPU,如 armv7s
、armv7
(我們當下流行的裝置基本都是iPhone5s以上了,通常我們直接arm64就夠用了)
4、在Build Phases中設定需要公開和需要隱藏的標頭檔案
5、將標頭檔案引入到NKTestOCFramework
(自己SDK的標頭檔案)
6、Command + B
執行專案,在Product
中找到framework
(在Xcode14建立的工程中,我們找不到Product
資料夾,需要做如下調整:)
- 1、找到.xcodeproj檔案
- 2、右鍵顯示包內容
- 3、找到project.pbxproj並雙擊開啟
- 4、在檔案內搜尋productRefGroup,旁邊還有一個mainGroup,把mainGroup後邊的值複製一下替換到productRefGroup後邊,然後關閉檔案並且儲存。
3.framework的使用將封裝好的.framework
拉入需要使用的專案中
4.工程執行
想要對Demo進行執行實踐的朋友,可以通過以下連結,下載: - http://github.com/LuckyVan37/iOS-SDK-Development
三、二進位制包的架構檢查,包的合併與拆分
1、相關概念以及常規處理
- 二進位制包檔案都是 Mach-O 檔案的一種(可以通過這篇文章簡單瞭解Mach-O檔案)
- iOS 的 二進位制包 檔案 分為
fat
二進位制檔案 和thin
二進位制檔案- 胖二進位制檔案:包含多套指令集架構的Mach-O檔案(比如同時包含
armv7
、armv7s
、armv64
、i386
、x86_64
其中的兩種以上) - thin二進位制檔案: 僅包含一套指令集架構的Mach-O檔案
- 胖二進位制檔案:包含多套指令集架構的Mach-O檔案(比如同時包含
- 二進位制檔案處理:
lipo -info
: 檢查二進位制檔案支援的架構c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -info + 二進位制檔案路徑
lipo -remove
: 移除二進位制檔案支援的某架構c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -remove + 要刪除的指令集架構 + 二進位制檔案路徑 + -output + 輸出的二進位制檔案路徑 如: lipo -remove armv7 origin_xxx.a -output op_xxx.a // 刪除靜態庫包括的armv7平臺
lipo -thin
: 匯出二進位制檔案支援的某架構c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -thin + 要匯出的指令集架構 + 二進位制檔案路徑 -output + 輸出的二進位制檔案路徑 如: lipo -thin arm64 origin_xxx.a -output op_xxx.a // 拆分靜態庫,只保留arm64 CPU架構
lipo -create
: 建立一個fat二進位制檔案使其支援的多個架構c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -create + 二進位制檔案路徑1 + 二進位制檔案路徑2 -output 輸出的二進位制檔案路徑 如: lipo -create device_xxx.a simulator_xxx.a -output universal_xxx.a //對真機或者模擬器分別打出 .a 檔案合併
2. 瞭解XCFramework
快速瞭解XCFramework: \ 官方視訊連結:http://developer.apple.com/videos/play/wwdc2019/416/ 官方文件連結:http://developer.apple.com/documentation/xcode/creating-a-multi-platform-binary-framework-bundle - XCFramework 是蘋果新出的庫型別,在 Xcode 11 及 cocoapods 1.9 以上版本被支援 - 與普通動態庫/靜態庫最大的區別是將多個平臺的二進位制庫,捆綁到一個可分發的
.xcframework
捆綁包中,支援所有的蘋果平臺和架構。 - 這裡的關鍵詞是多個平臺(iOS, macOS, tvOS, watchOS, iPadOS, carPlayOS) - 我們使用的普通動態庫/靜態庫屬於fat file
,僅僅是包含多個架構,如armv7 armv7s arm64 arm64e x86_64
等 - XCFramework 可以包含 iOS 裝置,iOS 模擬器和 Mac Catalyst 等多個平臺的二進位制庫。 - XCFramework庫是把不同平臺、不同架構的Framework庫放在一起(與Framework的開發相同,支援C、OC、C++、Swift)
3. 終端指令製作XCFramework
通過xcodebuild -create-xcframework
命令即可完成製作 XCFramework
示例如下:
c++
.
├── ios_arm64
│ ├── 0CD1FB8D-9D63-3092-B68B-2E579A306D3F.bcsymbolmap
│ ├── NKTestOCFramework.framework
│ └── NKTestOCFramework.framework.dSYM
└── ios_simulator_x86-64_arm64
├── NKTestOCFramework.framework
└── NKTestOCFramework.framework.dSYM
通過xcodebuild -create-xcframework
命令來合併為 XCFramework。
c++
xcodebuild -create-xcframework\
-framework ios_arm64/NKTestOCFramework.framework\
-framework ios_simulator_x86-64_arm64/NKTestOCFramework.framework\
-output NKTestOCFramework.xcframework
合併後的 NKTestOCFramework.xcframework 目錄結構如下,包含 arm64
和 x86_64
版本,這和 lipo 操作類似,合併其他平臺時操作類似。
c++
NKTestOCFramework.xcframework
├── Info.plist
├── ios-arm64
│ └── NKTestOCFramework.framework
└── ios-x86_64-simulator
└── NKTestOCFramework.framework
如果是靜態庫 .a 檔案,則需要用-library
和-headers
來指定靜態庫和標頭檔案。
c++
xcodebuild -create-xcframework\
-library ios-arm64/libNKTestOCLib.a\
-headers ios-arm64/include/NKTestOCLib\
-library ios-simulator-arm64-x86_64/libNKTestOCLib.a\
-headers ios-simulator-arm64-x86_64/include/NKTestOCLib\
-output NKTestOCLib.xcframework
- 03-iOS架構設計|iOS元件化開發-依賴包管理工具Cocoapods常用實踐:元件庫(本地庫、遠端庫(公有、私有))建立、模板工程、劃分、資源管理、優化等
- 04-iOS架構設計|iOS開發包二進位制化【.a靜態庫、,.framework(靜態庫、動態庫)、.dyld動態庫、XCFameworks等】
- 03-SwiftUI|構建列表與導航Building Lists and Navigation
- 21-探究iOS底層原理|多執行緒技術【瞭解iOS中的10個執行緒鎖,與執行緒鎖型別:自旋鎖、互斥鎖、遞迴鎖】
- 18-探究iOS底層原理|多執行緒技術【GCD原始碼分析1:dispatch_get_global_queue與dispatch_(a)sync、單例、執行緒死鎖】
- 19-探究iOS底層原理|多執行緒技術【GCD原始碼分析2:柵欄函式dispatch_barrier_(a)sync、訊號量dispatch_semaphore】
- 22-探究iOS底層原理|多執行緒技術【原子鎖atomic、gcd Timer、NSTimer、CADisplayLink】
- 20-探究iOS底層原理|多執行緒技術【GCD原始碼分析3:執行緒排程組dispatch_group、事件源dispatch Source】
- 14-探究iOS底層原理|Runtime的相關應用
- 13-探究iOS底層原理|Runtime【objc_msgSend的三個階段(訊息傳送、動態解析方法、訊息轉發)、super的本質】
- 12-探究iOS底層原理|Runtime【isa詳解、class的結構、方法快取cache_t】
- 11-探究iOS底層原理|探索Block的本質【Block的資料型別(本質)與記憶體佈局、變數捕獲、Block的種類、記憶體管理、Block的修飾符、迴圈引用】
- 04-探究iOS底層原理|ARM64彙編
- 07-探究iOS底層原理|幾種OC物件【例項物件、類物件、元類】、物件的isa指標、superclass、物件的方法呼叫、Class的底層本質
- 03-探究iOS底層原理|LLDB【命令結構、查詢命令、斷點設定、流程控制、模組查詢、記憶體讀寫、chisel外掛】
- 06-探究iOS底層原理|OC物件的本質【底層實現、記憶體佈局、繼承關係】
- 05-探究iOS底層原理|OC的本質
- 02-探究iOS底層原理|編譯器LLVM專案【Clang、SwiftC、優化器、LLVM、Xcode編譯的過程】
- 03-iOS 效能優化|效能除錯工具Instruments-Leaks工具使用
- 04-iOS 效能優化|效能除錯工具Instruments-Allocations工具使用