04-iOS架構設計|iOS開發包二進位制化【.a靜態庫、,.framework(靜態庫、動態庫)、.dyld動態庫、XCFameworks等】

語言: CN / TW / HK

前言

我們之前通過一篇文章在討論“移動客戶端架構設計的時候,僅是通過一篇文章進行了綜述。\ 後來,我就換工作,來到了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,可以看到如下圖的設定項:

image.png

  • Architectures
    指定當前Target被編譯時支援的指令集的列表,如果指定了多個架構,機會生成多個架構需要的二進位制檔案。
  • Build Active Architecture Only
    指定是否只編譯當前連線裝置所支援的指令集。
    預設Debug時為YESRelease時為NO。設定為YES時,編譯後只生成當前連線裝置所支援的指令集程式碼,編譯速度更快。
  • Excluded Architectures
    指定當前Target被編譯時拒絕接納的指令集列表,編譯後最終生成的二進位制檔案支援的指令集是Architectures減去Excluded Architectures

二、開發二進位制化庫的實踐

我們前面有提及 靜態庫動態庫,的區別。我們這裡就不再重複介紹。\ 我們直接進入建立一個.framework靜態庫的實踐(此次我採用的是Xcode14.1,與之前的Xcode版本的建立過程總體上大致相似,略有不同。若是同學們用比較老的Xcode版本,請自行尋找相應教程)

1. 首先建立.frmawork專案

image.png

image.png

framewrok中可以封裝入自己需要封裝的內容

image.png 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

image.png

2、設定Build Setting引數 Mach-O Type 為Static Library (配置靜態、動態)

image.png

3、設定Build Setting引數 在Architectures下增加 需要適配的硬體CPU,如 armv7sarmv7(我們當下流行的裝置基本都是iPhone5s以上了,通常我們直接arm64就夠用了)

image.png

4、在Build Phases中設定需要公開和需要隱藏的標頭檔案 image.png

5、將標頭檔案引入到NKTestOCFramework (自己SDK的標頭檔案) image.png

6、Command + B執行專案,在Product中找到framework (在Xcode14建立的工程中,我們找不到Product資料夾,需要做如下調整:)

  • 1、找到.xcodeproj檔案
  • 2、右鍵顯示包內容
  • 3、找到project.pbxproj並雙擊開啟
  • 4、在檔案內搜尋productRefGroup,旁邊還有一個mainGroup,把mainGroup後邊的值複製一下替換到productRefGroup後邊,然後關閉檔案並且儲存。

image.png

3.framework的使用將封裝好的.framework拉入需要使用的專案中

image.png

image.png

4.工程執行

想要對Demo進行執行實踐的朋友,可以通過以下連結,下載: - http://github.com/LuckyVan37/iOS-SDK-Development

三、二進位制包的架構檢查,包的合併與拆分

1、相關概念以及常規處理

  • 二進位制包檔案都是 Mach-O 檔案的一種(可以通過這篇文章簡單瞭解Mach-O檔案)
  • iOS 的 二進位制包 檔案 分為 fat 二進位制檔案 和 thin 二進位制檔案
    • 胖二進位制檔案:包含多套指令集架構的Mach-O檔案(比如同時包含armv7armv7sarmv64i386x86_64其中的兩種以上)
    • thin二進位制檔案: 僅包含一套指令集架構的Mach-O檔案
  • 二進位制檔案處理:
    1. lipo -info: 檢查二進位制檔案支援的架構 c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -info + 二進位制檔案路徑
    2. lipo -remove: 移除二進位制檔案支援的某架構 c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -remove + 要刪除的指令集架構 + 二進位制檔案路徑 + -output + 輸出的二進位制檔案路徑 如: lipo -remove armv7 origin_xxx.a -output op_xxx.a // 刪除靜態庫包括的armv7平臺
    3. lipo -thin: 匯出二進位制檔案支援的某架構 c++ // 判斷靜態庫所支援的平臺 armv7 x86_64 arm64 lipo -thin + 要匯出的指令集架構 + 二進位制檔案路徑 -output + 輸出的二進位制檔案路徑 如: lipo -thin arm64 origin_xxx.a -output op_xxx.a // 拆分靜態庫,只保留arm64 CPU架構
    4. 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)image.png - 我們使用的普通動態庫/靜態庫屬於fat file,僅僅是包含多個架構,如armv7 armv7s arm64 arm64e x86_64等 - XCFramework 可以包含 iOS 裝置,iOS 模擬器和 Mac Catalyst 等多個平臺的二進位制庫。image.png - XCFramework庫是把不同平臺、不同架構的Framework庫放在一起(與Framework的開發相同,支援C、OC、C++、Swift)image.png

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。

image.png c++ xcodebuild -create-xcframework\ -framework ios_arm64/NKTestOCFramework.framework\ -framework ios_simulator_x86-64_arm64/NKTestOCFramework.framework\ -output NKTestOCFramework.xcframework

image.png

合併後的 NKTestOCFramework.xcframework 目錄結構如下,包含 arm64x86_64 版本,這和 lipo 操作類似,合併其他平臺時操作類似。 image.png c++ NKTestOCFramework.xcframework ├── Info.plist ├── ios-arm64 │   └── NKTestOCFramework.framework └── ios-x86_64-simulator └── NKTestOCFramework.framework

image.png 如果是靜態庫 .a 檔案,則需要用-library-headers來指定靜態庫和標頭檔案。

image.png 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

image.png

「其他文章」