打包靜態(tài)庫(源碼中包含其他靜態(tài)庫以及開源庫)

因為公司最近要把某一個功能模塊提供給第三方使用,所以就需要將涉及到的源碼打包成靜態(tài)庫(.a文件),但是。。。怎么打包呢,從來沒做過啊!谷歌了一上午,找到很多文章,寫的都很好,但是很少能有一篇,讓你看到就能徹底搞懂的。比如自己源碼中包含第三方靜態(tài)庫怎么辦?用到的圖片資源,Xib資源怎么辦?自己源碼依賴的第三方庫怎么處理才能不影響第三方對相同庫的升級及使用?這都是需要考慮的問題。關(guān)于靜態(tài)庫的介紹我就不普及了,直接一步步進行.a庫的創(chuàng)建:

#一、創(chuàng)建靜態(tài)庫工程

這一步應(yīng)該是很簡單的,比如項目名稱取為 YJEChatSDK。


Paste_Image.png

建好之后大概就是這個樣子:


Paste_Image.png

把工程里默認添加的類刪除(移到廢紙簍)就可以了,整個工程很干凈!

Paste_Image.png
#二、對工程進行必要的設(shè)置

1、支持的系統(tǒng)這里要選擇IOS哦(雖然默認就是)。。。

Paste_Image.png

2、Build Active Architecture Only選項,當它設(shè)置為Yes時,是為了debug的時候編譯速度更快,此時它只編譯當前的architecture版本。 而設(shè)置為No時,會編譯所有的版本。這里我們要設(shè)置為NO。

Paste_Image.png

3、如果你的源碼中使用了類別(category),就要在 Other Linker Flags 中添加 -ObjC或者-all_load 。

Paste_Image.png

Unix的標準靜態(tài)庫實現(xiàn)和Objective-C的動態(tài)特性之間有一些沖突:Objective-C沒有為每個函數(shù)(或者方法)定義鏈接符號,它只為每個類創(chuàng)建鏈接符號。這樣當在一個靜態(tài)庫中使用類別來擴展已有類的時候,鏈接器不知道如何把類原有的方法和類別中的方法整合起來,就會導(dǎo)致你調(diào)用類別中的方法時,出現(xiàn)"selector not recognized",也就是找不到方法定義的錯誤。為了解決這個問題,引入了-ObjC標志,它的作用就是將靜態(tài)庫中所有的和對象相關(guān)的文件都加載進來。

本來這樣就可以解決問題了,不過在64位的Mac系統(tǒng)或者iOS系統(tǒng)下,鏈接器有一個bug,會導(dǎo)致只包含有類別的靜態(tài)庫無法使用-ObjC標志來加載文件,變通方法就是使用-all_load 。

4、選擇release


Paste_Image.png
Paste_Image.png

到此為止對于工程的基本設(shè)置算是完了,當然根據(jù)自己的需求也許還有其他的設(shè)置。

#三、添加代碼文件

注意下,打包靜態(tài)庫的時候并不能包含資源文件,即使我們將資源文件(.png文件或者Xib文件)拷貝到靜態(tài)庫工程中,但實際上這些資源是不會添加到target的,也就是說編譯結(jié)果中并不包含這些資源,因此如果有人調(diào)用你制作的這個靜態(tài)庫,所有的資源(圖片、Xib)都是缺失的。

針對這種情況,我們將代碼文件和資源文件分開考慮,首先是代碼文件的打包:
1、添加自己的代碼和私有庫
把自己的源碼以及私有庫(不包括第三方開源庫,因為開源庫誰都可以去下載使用,沒必要也不應(yīng)該打包進去)放到工程中。

如果你的源碼或者私有庫又使用了第三方的靜態(tài)庫,打包的時候并不能靜態(tài)庫中包含靜態(tài)庫,所以只需要把第三方靜態(tài)庫的頭文件放進我們的工程就好,而不需要將.a文件也添加進來。需要注意的是,最后使用時,要把我們的.a庫和第三方的這個.a庫一起放進項目。

Paste_Image.png

2、添加依賴的開源庫
如果我們的源碼依賴一些開源庫,比如AFNetWorking,Mansory等,就需要將它們打包進來,不過這樣一來,容易給使用者帶來問題,比如開源庫的沖突,版本不兼容等。

所以我的處理辦法是,只添加這些開源庫的頭文件,然后告訴使用者我們的靜態(tài)庫是依賴這些開源庫的,讓他們自己下載相應(yīng)的框架。這樣做的好處是,方便第三方使用者隨意升級自己的開源庫而不用擔心會跟靜態(tài)庫中的開源庫引起沖突,而且就算使用者升級了開源庫的版本,也一般不會改變頭文件里面的接口(高版本總會兼容低版本),所以不會影響我們的靜態(tài)庫。

Paste_Image.png

3、暴露出相應(yīng)的接口(頭文件),供第三方使用
我們打包靜態(tài)庫肯定是要給人用的,所以需要暴露出設(shè)計好的頭文件供別人使用。靜態(tài)工程里需要編譯的所有源文件都會包含在Compile Source中,如下圖所示:

Paste_Image.png

而需要暴露出來的頭文件添加在Copy Files選項中,如下圖所示:

Paste_Image.png

到此為止基本上完成了打包的準備工作,下面開始編譯。

#四、編譯生成靜態(tài)庫

根據(jù)需要,如果要在模擬器下使用靜態(tài)庫,編譯時就選擇模擬器,在真機中使用,編譯時就選擇真機。


Paste_Image.png
Paste_Image.png

這里我在模擬器和真機下分別運行了一次,得到兩個.a文件,真機和模擬器:

Paste_Image.png

一般將靜態(tài)庫給別人使用時,要同時給真機版和模擬器版,給兩個文件肯定是不方便的,所以要把兩個版本合并為一個.a文件,這樣不管真機還是模擬器,都可以運行。

打開終端,可以先查看下.a庫支持的架構(gòu),輸入 lipo -info 靜態(tài)庫路徑,靜態(tài)庫路徑這里直接把文件拖進來就好。

Paste_Image.png

很顯然,armv7和arm64表示32位和64位真機,i386和x86_64表示32位和64位模擬器(mac的架構(gòu))。下面使用命令將真機版和模擬器版本合并:
lipo -create 靜態(tài)庫路徑1 靜態(tài)庫路徑2 -output /Users/yangjie/Desktop/YJEChatSDK.a

Paste_Image.png

最終得到需要的YJEChatSDK.a文件。

#處理資源文件(圖片.png和Xib文件)

*首先僅考慮圖片
如果代碼中使用了一些圖片資源,怎么樣才能正確讀取這些圖片呢?我的做法是(我不太清楚是不是還有其他辦法):在桌面新建一個文件夾,將用到的所有圖片放進去,然后把文件夾的名字改為:文件名稱.Bundle。比如我這里就改為YJsdkBundle.Bundle。這樣在使用靜態(tài)庫時,直接將該Bundle文件一起放進工程就可以了。

Paste_Image.png

然而這樣還是不行的,因為靜態(tài)庫中的代碼依然找不到圖片資源的路徑,所以還是不能正確加載。我們需要重新返回代碼,在代碼中添加兩個宏定義:

define BUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"YJsdkBundle.Bundle"]
define YJImageNamed(imageName)  ([UIImage imageNamed:[NSString stringWithFormat:@"%@/%@",BUNDLE_PATH,imageName]])

將所有加載圖片的方法[UIImage imageNamed:]替換為我們定義的宏,比如我這里是YJImageNamed(圖片名稱),需要注意的是,圖片名稱要跟Bundle文件中圖片名稱對應(yīng)(后綴@2x或者@3x不用加)。我這里的Bundle文件內(nèi)并沒有子文件夾,所以宏定義中,stringWithFormat:@"%@/%@",BUNDLE_PATH,imageName這么寫,如果你的Bundle文件下還有子文件夾,應(yīng)該這么寫:
stringWithFormat:@"%@/文件夾名稱/%@",BUNDLE_PATH,imageName

這樣,圖片就可以正確加載了!

關(guān)于Xib文件
對于Xib文件,我并沒有親自嘗試,所以。。。沒有發(fā)言權(quán)了,大家可以谷歌一下。(
__*)

打包好之后,使用時編譯連接錯誤問題:

Paste_Image.png
Paste_Image.png

類似這種奇怪的錯誤,我遇到了,原因是,1、沒有引入必要的系統(tǒng)框架。2、靜態(tài)庫已經(jīng)包含了某些文件,使用的時候,又引入了這些文件,造成duplicate錯誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容