iOS - 靜態庫.a 和 framework 詳解

kaaaaai發表於2018-09-17

一、基本概念

1.什麼是庫?

庫是共享程式程式碼的方式,一般分為靜態庫和動態庫。

2.靜態庫與動態庫的區別?

(1)靜態庫:之所以叫做靜態,是因為靜態庫在編譯的時候會被直接拷貝一份,複製到目標程式裡,這段程式碼在目標程式裡就不會再改變了。

靜態庫的好處很明顯,編譯完成之後,庫檔案實際上就沒有作用了。目標程式沒有外部依賴,直接就可以執行。當然其缺點也很明顯,就是會使用目標程式的體積增大。被多次使用就有多份冗餘拷貝。

(2)動態庫:連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫,系統只載入一次,多個程式共用,節省記憶體。

動態庫的優點是,不需要拷貝到目標程式中,不會影響目標程式的體積,而且同一份庫可以被多個程式使用(因為這個原因,動態庫也被稱作共享庫)。同時,編譯時才載入的特性,也可以讓我們隨時對庫進行替換,而不需要重新編譯程式碼。動態庫帶來的問題主要是,動態載入會帶來一部分效能損失,使用動態庫也會使得程式依賴於外部環境。如果環境缺少動態庫或者庫的版本不正確,就會導致程式無法執行(Linux 下常見 lib not found 錯誤)。

在 iOS8 之後,蘋果開始支援開發自己的 framework

此時自己構建的 framework 和系統的 framework 還是有區別的,系統的 framework 並不需要複製到目標程式。 自己開發的 framework 無論是動態還是靜態的,都要複製到目標程式,所以蘋果又把這個叫做 embeded framework

3.iOS 裡靜態庫形式?

.a.framework

4.iOS 裡動態庫形式?

.dylib.framework

5.framework 為什麼既是靜態庫又是動態庫?

系統的.framework 是動態庫,我們自己建立的.framework 是靜態庫。

6.a與.framework 有什麼區別?

.a 是一個純二進位制檔案,.framework 中除了有二進位制檔案之外還有資原始檔。

.a 檔案不能直接使用,至少要有.h檔案配合,.framework 檔案可以直接使用。

.a + .h + sourceFile = .framework

建議用.framework

7.為什麼要使用靜態庫?

方便共享程式碼,便於合理使用。

實現 iOS 程式的模組化。可以把固定的業務模組化成靜態庫。

和別人分享你的程式碼庫,但不想讓別人看到你程式碼的實現。

開發第三方 sdk 的需要。

8.製作靜態庫時的幾點注意:

1 注意理解:無論是.a 靜態庫還.framework 靜態庫,我們需要的都是二進位制檔案+.h+其它資原始檔的形式,不同的是,.a 本身就是二進位制檔案,需要我們自己配上.h 和其它檔案才能使用,而.framework 本身已經包含了.h 和其它檔案,可以直接使用。

2 圖片資源的處理:兩種靜態庫,一般都是把圖片檔案單獨的放在一個.bundle 檔案中,一般.bundle 的名字和.a.framework 的名字相同。.bundle 檔案很好弄,新建一個資料夾,把它改名為.bundle 就可以了,右鍵,顯示包內容可以向其中新增圖片資源。

3 category 是我們實際開發專案中經常用到的,把 category 打成靜態庫是沒有問題的,但是在用這個靜態庫的工程中,呼叫 category 中的方法時會有找不到該方法的執行時錯誤(selector not recognized),解決辦法是:在使用靜態庫的工程中配置 other linker flags 的值為-ObjC

4 如果一個靜態庫很複雜,需要暴露的.h 比較多的話,就可以在靜態庫的內部建立一個.h 檔案(一般這個.h 檔案的名字和靜態庫的名字相同),然後把所有需要暴露出來的.h 檔案都集中放在這個.h 檔案中,而那些原本需要暴露的.h 都不需要再暴露了,只需要把.h 暴露出來就可以了。

二、製作.a 靜態庫

1.新建工程,選擇 Cocoa Touch Static Library,建立.a 靜態庫

![041_01](http://os1i62usc.bkt.clouddn.com/041_01.jpg)
![042_02](http://os1i62usc.bkt.clouddn.com/042_02.jpg)

2.配置工程環境

2.1 配置最低支援版本

![041_03](http://os1i62usc.bkt.clouddn.com/041_03.jpg)

2.2 設定適配所有模擬器架構重要

project -> buildSeting -> Build Active Architecture Only 設為NO

![041_04](http://os1i62usc.bkt.clouddn.com/041_04.jpg)

Build Active Architecture Only:指定是否只對當前連線裝置所支援的指令集編譯 設定為 YES,是為了 Debug 的時候編譯速度更快,它只編譯當前的 Architecture 版本,而設定為 NO 時,會編譯所有的版本。 所以,一般預設 Debug 設定為 YES,Release 時為 NO,以適應不同裝置。但是我們是在 Debug 模式下建立所有機型都可執行的靜態庫,所以我們要把 Bebug 下設定 NO。若為 YES,那麼編譯出來的.a 靜態庫就只包含當前裝置的指令集。

3.新增自己要封裝的檔案

標頭檔案最好一起放在一個.h 檔案中,方便使用時只匯入一個h 檔案,這裡放在 TestStaticHeader 裡;

如果需要用到圖片,可以新增 Bundle 檔案:

![041_05](http://os1i62usc.bkt.clouddn.com/041_05.gif)

4.修改專案配置,把要暴露的 .h 檔案,新增到 Target-> Build Phases -> Copy Files

![041_06](http://os1i62usc.bkt.clouddn.com/041_06.gif)

新增暴露的標頭檔案的另一種方式,是新增 Headers 裡的 Public 中:

![041_07](http://os1i62usc.bkt.clouddn.com/041_07.jpg)
![041_08](http://os1i62usc.bkt.clouddn.com/041_08.jpg)

5.生成.a 檔案

此處注意需要生成 4 個

5.1修改環境

![041_09](http://os1i62usc.bkt.clouddn.com/041_09.jpg)
![041_10](http://os1i62usc.bkt.clouddn.com/041_10.jpg)

5.2 選擇模擬器+Debug 環境+“cmd+R”生成.a

![041_11](http://os1i62usc.bkt.clouddn.com/041_11.jpg)

此處注意需要生成4個 如此類推打出四種.a

  • 真機-Debug版本
  • 真機-Release版本
  • 模擬器-Debug版本
  • 模擬器-Release版本

最終生成結果:

![041_12](http://os1i62usc.bkt.clouddn.com/041_12.jpg)

5.3 合併 debug 兩個包和 release 兩個包

注意:這裡的合併指的是 1.debug 下真機+模擬器合併 2.release 下真機+模擬器合併

(1)將4個.a檔案拷貝到單獨資料夾

![041_13](http://os1i62usc.bkt.clouddn.com/041_13.jpg)

(2)合併

開啟終端,切到上述資料夾目錄,執行以下語句

lipo -create+空格+模擬器Debug路徑+空格+模擬器Release路徑+空格-output+空格+輸出路徑+輸出名字(可自定義)
複製程式碼
![041_14](http://os1i62usc.bkt.clouddn.com/041_14.jpg)

同理 release 也是如此,最後生成兩個檔案

![041_15](http://os1i62usc.bkt.clouddn.com/041_15.jpg)

好了,這樣就建立完.a 靜態庫了,使用的時候,只需在工程中匯入.a 檔案和暴露的.h 檔案,配置 Header search path 路徑就可以了。

注意:如果靜態庫中有 category 類,則在使用靜態庫的專案配置中【Other Linker Flags】需要新增引數【-ObjC]或者【-all_load】。 為了開發方便,我們可以使用生成的通用靜態庫,但是最終上線的使用我們可以只匯入真機的,這樣工程的體積也會小一些。

三、製作 framework 靜態庫

1.新建 framework 工程

![041_16](http://os1i62usc.bkt.clouddn.com/041_16.jpg)

2.新建檔案類

![041_17](http://os1i62usc.bkt.clouddn.com/041_17.jpg)

3.修改工程檔案配置

build setting ->搜尋 mach -> 修改 mach -O Type ->static Library

![041_18](http://os1i62usc.bkt.clouddn.com/041_18.jpg)
![041_19](http://os1i62usc.bkt.clouddn.com/041_19.jpg)

⚠️注意:如果需要匯入第三方靜態庫,在拖入工程新增的時候,不要勾選新增到target中。

4.暴露標頭檔案

![041_20](http://os1i62usc.bkt.clouddn.com/041_20.jpg)

5.生成 .framework

5.1 修改環境

![041_21](http://os1i62usc.bkt.clouddn.com/041_21.jpg)

這裡可以選擇 Debug 和 Release 環境

![041_22](http://os1i62usc.bkt.clouddn.com/041_22.jpg)

5.2 選擇模擬器+Debug 環境+“cmd+R”生成.a

![041_23](http://os1i62usc.bkt.clouddn.com/041_23.jpg)

此處注意需要生成4個 如此類推打出四種.framework

  • 真機-Debug版本
  • 真機-Release版本
  • 模擬器-Debug版本
  • 模擬器-Release版本

最終生成結果

![041_24](http://os1i62usc.bkt.clouddn.com/041_24.jpg)

6.合併 debug 兩個包和 release 兩個包

注意:這裡的合併指的是 1.debug 下真機+模擬器合併 2.release 下真機+模擬器合併

6.1 將 4 個 .framework 檔案拷貝到單獨資料夾

![041_25](http://os1i62usc.bkt.clouddn.com/041_25.jpg)

6.2 合併

開啟終端,輸入命令規則

lipo -create+空格+模擬器Debug路徑+空格+模擬器Release路徑+空格-output+空格+輸出路徑+輸出名字(可自定義)

//For example:
lipo -create /Users/Kaaaaai/Desktop/frameworkProduct/TestStatic_framework-Debug-iphoneos /Users/Kaaaaai/Desktop/frameworkProduct/TestStatic_framework-Debug-iphonesimulator -output /Users/Kaaaaai/Desktop/frameworkProduct/TestStatic_framework-Debug
複製程式碼

同理 release 也是如此,最後生成兩個檔案。

![041_26](http://os1i62usc.bkt.clouddn.com/041_26.jpg)

6.3替換檔案

(1)尋找之前生成的 任意framework (2)替換二進位制檔案

替換前:

![041_27](http://os1i62usc.bkt.clouddn.com/041_27.jpg)

替換後:

![041_28](http://os1i62usc.bkt.clouddn.com/041_28.jpg)

大功告成。

原文連結:iOS - 靜態庫.a 和 framework 詳解

相關文章