1. 程式人生 > >iOS建立.a和.framework靜態庫,以及Bundle資原始檔的使用

iOS建立.a和.framework靜態庫,以及Bundle資原始檔的使用

引言

在開發中.framework靜態庫還是比較常見的,比如:SDK,公司間的程式碼合作等。我們可以把一些不願意讓別人見到的程式碼,用靜態庫的方式把它隱藏起來,只留下.h檔案顯示方法供程式設計人員使用。而.a檔案出了靜態庫本身外,還需要引入.h檔案,而.framework就不需要如此,由於.framework的方便性所以一般情況下我們見到的較多。

什麼是庫

庫從本質上來說是一種可執行程式碼的二進位制格式,可以被載入記憶體中執行。庫分靜態庫和動態庫兩種。
iOS中的靜態庫有 .a 和 .framework兩種形式;動態庫有.dylib 和 .framework 形式,後來.dylib動態庫又被蘋果替換成.tbd的形式。

靜態庫與動態庫的區別

靜態庫和動態庫是相對編譯期和執行期的:靜態庫在程式編譯時會被連結到目的碼中,程式執行時將不再需要改靜態庫;而動態庫在程式編譯時並不會被連結到目的碼中,只是在程式執行時才被載入,因為在程式執行期間還需要動態庫的存在。

Bundle檔案

Bundle檔案可以用於存放資原始檔,可用於多人合作開發,避免資源重名。裡面可以儲存xib文、資源圖片等。Bundle檔案是靜態的,不進行編譯的。所以使用Bundle中的資源,就需要找到相應的資源路徑。另外,我看別人部落格上是說,.a檔案中是無法用Bundle檔案的,只能另存一個檔案;Framework靜態庫可以用Bundle檔案;我也沒試過,請試過的小夥伴留言告訴我,我就偷個懶,嘿嘿

總結:同一個靜態庫在不同程式中使用時,每一個程式中都得匯入一次,打包時也被打包進去,形成一個程式。而動態庫在不同程式中,打包時並沒有被打包進去,只在程式執行使用時,才連結載入(如系統的框架如UIKit、Foundation等),所以程式體積會小很多,但是蘋果不讓使用自己的動態庫,否則稽核就無法通過。

一、建立 .a 靜態庫

1. 新建工程。比如我們的工程名叫PSSTest,那麼我們建立的.a靜態庫的名字最好就是前面加個lib,如libPSSTest.a。

  • 新建工程 (選中xcode,按commond + shift + N)
    圖

  • 此時工程目錄是這個樣子,.a檔案還沒有被建立,因此是紅色的
    圖

  • 你可以把圖中 libPSSTest.h.m 換成你自己要生成庫的檔案(可以是多個),在這裡我就不換了,就用這兩個檔案,我們在.h檔案中新增一個方法+sayHello,並在.m中實現它

// 一定要記得在.h中宣告哦
+ (void)sayHello
{
    NSLog(@".a靜態庫:Hello, world!");
}

2. 新增Headers


  • 按照下圖順序進行操作
    圖
    圖
    圖
    圖
    圖

這裡需要注意的是暴露出來的標頭檔案中import的其他類也得新增到public中暴露出來。
如果不想將import的類暴露出來,那麼在標頭檔案中用@class 然後在對應的.m檔案中再import。
總之
1. 你再外面用到的類,一定要暴露出來;
2. 你暴露出來的類,標頭檔案中匯入的類也一定是暴露出來的
3. 如果提示匯入標頭檔案報錯,找不到檔案,找不到誰暴露誰就對了

3. 進行打包前的一些配置

  • 設定編譯模式,開啟xcode選單Product -> Scheme -> Edit Scheme,改成release模式,如下圖
    圖

  • 編譯機器的選擇,如下圖,一定要選擇NO。(如果選擇yes,生成部分機型,選擇NO則適配所有機型,想了解更多,請自行百度,總之,選NO就對了)
    圖

4. 接下來,我們進行打包

操作簡述:
1. 在真機情況下編譯 (Generic iOS Device),並記錄下.a檔案的絕對路徑
2. 在模擬機情況下編譯(隨便吧,別賤嗖嗖的用iPhone4,雖然我也沒試過有沒有問題吧,有興趣可以試試[emj壞笑]),並記錄下.a檔案絕對路徑
3. 用命令列合併1、2部記錄的檔案,到新的.a檔案,名字最好取開始我們取的名字吧,命令列:lipo -create 檔案1路徑 檔案2路徑 -output 最終檔案路徑
4. 把你要暴露的.h檔案和你已經生成的.a檔案搞到一個資料夾裡,這個資料夾就可以直接拖到工程裡用啦

4.1 在真機情況下編譯 (Generic iOS Device),並記錄下.a檔案的絕對路徑
4.1

4.2 在模擬機情況下編譯,並記錄下.a檔案絕對路徑,本操作和上步操作一模一樣,只不過需要選擇一個模擬器,隨便選吧,我是選的iPhone7P,不截圖了

4.3 使用命令列,合併剛剛記錄的兩個路徑,到另一個路徑,例如:

lipo -create /Users/xxxxx/Library/Developer/Xcode/DerivedData/libPSSTest-bmfbhsxiqeajiigltpqjlxhhpjjh/Build/Products/Release-iphoneos/liblibPSSTest.a空格/Users/shanhexia/Library/Developer/Xcode/DerivedData/libPSSTest-bmfbhsxiqeajiigltpqjlxhhpjjh/Build/Products/Release-iphonesimulator/liblibPSSTest.a -output /Users/shanhexia/Desktop/libPSSTest.a

我是把合成之後的.a檔案放到桌面上了

4.4 也是最後一步,把我們剛合成的.a檔案和想要暴露的.h檔案,弄到一個資料夾下
新建一個資料夾,取名libPSSTest,把檔案複製貼上進來,如下圖
圖

4.5 建立.a靜態庫就已經建立完了,我們來試試吧,匯入剛剛4.4建立的資料夾,匯入標頭檔案,呼叫方法看看有沒有列印
看,我們成功了

4.6 補充:

  1. category是我們實際開發專案中經常用到的,把category打成靜態庫是沒有問題的,但是在用這個靜態庫的工程中,呼叫category中的方法時會有找不到該方法的執行時錯誤(selector not recognized),解決辦法是:在使用靜態庫的工程中配置other linker flags的值為-ObjC。
  2. 如果一個靜態庫很複雜,需要暴露的.h比較多的話,就可以在靜態庫的內部建立一個.h檔案(一般這個.h檔案的名字和靜態庫的名字相同),然後把所有需要暴露出來的.h檔案都集中放在這個.h檔案中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出來就可以了。

二、建立.Framework靜態庫

1. 新建工程。比如我們的工程名叫PSSFramework

  • 新建工程 (選中xcode,按commond + shift + N)
    圖

  • 新增檔案到工程,並且在PSSFramework.h檔案中匯入介面檔案
    圖片.png

  • 在PSSObject中新增+sayHello方法,並在.m中實現

// 一定要在`.h`中暴露方法哦
+ (void)sayHello
{
    NSLog(@".framework: Hello, world!");
}

2. 新增Headers

  • 這一步和建立.a的時候一模一樣,請往上翻。不過跟.a不同的是,貌似它裡面本來就有Headers了,但是隻給你暴露了一個.h檔案,需要多暴露的話再自己拖吧

3. 打包前的一些配置

  • 設定編譯模式,開啟xcode選單Product -> Scheme -> Edit Scheme,改成release模式,如下圖(這一步和生成.a一樣,我就借用圖了)
    圖

  • 編譯機器的選擇,如下圖,一定要選擇NO。(這一步和生成.a一樣,我就借用圖了)
    圖

  • 修改生成的Mach-O格式(很重要)

圖片.png

4. 打包Framework (合併模擬器版framework和真機版framework)

  • 分別在真機(Generic iOS Device)和模擬器編譯,這次不用記錄路徑,一會我會標出合併哪兩個檔案
    注意: 合併的命令同上面相似,不同之處是:framework靜態庫合併的不是framework,而是framework下的一個二進位制檔案,即下圖中我標出來的檔案。
    lipo -create 第一個framework下二進位制檔案的絕對路徑 第二個framework下二進位制檔案的絕對路徑 -output 最終的二進位制檔案路徑。
    圖片.png
    圖片.png

  • 接下來我們進行合併,我們把新合併的二進位制檔案放到Release-iphoneosRelease-iphonesimulator同一個資料夾下

    命令列如下
    lipo -create /Users/xxxxx/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/Release-iphoneos/PSSFramework.framework/PSSFramework /Users/shanhexia/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/Release-iphonesimulator/PSSFramework.framework/PSSFramework -output /Users/shanhexia/Library/Developer/Xcode/DerivedData/PSSFramework-ehyytcfdvluxetbnmqcfzosxrbtu/Build/Products/PSSFramework

  • 圖片.png

  • 通過上一步,我們已經把我們要的Framework搞到桌面上了,接下來我們就試試能不能用吧。將Framework拖進工程,匯入框架,呼叫方法,看看有沒有列印

    我試了,確實是能用,不截圖了

三、Bundle檔案的使用

1. 建立Bundle

桌面上建立一個資料夾,把資料夾的字尾改為. bundle這時他就變成一個bundle檔案了,這時我們右鍵顯示包內容就可以把對應的圖片資源等放進檔案中,然後把他丟進工程中就可以使用了。

2. 使用方法 (親測可用)

圖片.png



結束語

實際上,在專案中,我們用別人的Framework.a比較多一些,開發自己的專案的時候,我倒是沒怎麼用到過,但是公司如果希望一部分程式碼需要保密,是可以用這種方式的。或者你開發了一個功能,不想開源,也可以這樣搞(雖然應該可以反編譯,反正我不會),但是我不推薦;畢竟大家把自己的程式碼開源可以互相促進彼此的成長嘛,嘿嘿^_^

如果覺得寫得還行,點個Star唄
同時也歡迎評論中指出本文存在的bug,或者疑問,互相促進!
作者郵箱:[email protected]
github地址:https://github.com/Pangshishan
qq/微信: 704158807