因為公司最近要把某一個功能子產品提供給第三方使用,是以就需要将涉及到的源碼打包成靜态庫(.a檔案),但是。。。怎麼打包呢,從來沒做過啊!谷歌了一上午,找到很多文章,寫的都很好,但是很少能有一篇,讓你看到就能徹底搞懂的。比如自己源碼中包含第三方靜态庫怎麼辦?用到的圖檔資源,Xib資源怎麼辦?自己源碼依賴的第三方庫怎麼處理才能不影響第三方對相同庫的更新及使用?這都是需要考慮的問題。關于靜态庫的介紹我就不普及了,直接一步步進行.a庫的建立:
#一、建立靜态庫工程
這一步應該是很簡單的,比如項目名稱取為 YJEChatSDK。
建好之後大概就是這個樣子:
把工程裡預設添加的類删除(移到廢紙簍)就可以了,整個工程很幹淨!
#二、對工程進行必要的設定
1、支援的系統這裡要選擇IOS哦(雖然預設就是)。。。
2、Build Active Architecture Only選項,當它設定為Yes時,是為了debug的時候編譯速度更快,此時它隻編譯目前的architecture版本。 而設定為No時,會編譯所有的版本。這裡我們要設定為NO。
3、如果你的源碼中使用了類别(category),就要在 Other Linker Flags 中添加 -ObjC或者-all_load 。
Unix的标準靜态庫實作和Objective-C的動态特性之間有一些沖突:Objective-C沒有為每個函數(或者方法)定義連結符号,它隻為每個類建立連結符号。這樣當在一個靜态庫中使用類别來擴充已有類的時候,連結器不知道如何把類原有的方法和類别中的方法整合起來,就會導緻你調用類别中的方法時,出現"selector not recognized",也就是找不到方法定義的錯誤。為了解決這個問題,引入了-ObjC标志,它的作用就是将靜态庫中所有的和對象相關的檔案都加載進來。
本來這樣就可以解決問題了,不過在64位的Mac系統或者iOS系統下,連結器有一個bug,會導緻隻包含有類别的靜态庫無法使用-ObjC标志來加載檔案,變通方法就是使用-all_load 。
4、選擇release
Paste_Image.png
到此為止對于工程的基本設定算是完了,當然根據自己的需求也許還有其他的設定。
#三、添加代碼檔案
注意下,打包靜态庫的時候并不能包含資源檔案,即使我們将資源檔案(.png檔案或者Xib檔案)拷貝到靜态庫工程中,但實際上這些資源是不會添加到target的,也就是說編譯結果中并不包含這些資源,是以如果有人調用你制作的這個靜态庫,所有的資源(圖檔、Xib)都是缺失的。
針對這種情況,我們将代碼檔案和資源檔案分開考慮,首先是代碼檔案的打包:
1、添加自己的代碼和私有庫
把自己的源碼以及私有庫(不包括第三方開源庫,因為開源庫誰都可以去下載下傳使用,沒必要也不應該打包進去)放到工程中。
如果你的源碼或者私有庫又使用了第三方的靜态庫,打包的時候并不能靜态庫中包含靜态庫,是以隻需要把第三方靜态庫的頭檔案放進我們的工程就好,而不需要将.a檔案也添加進來。需要注意的是,最後使用時,要把我們的.a庫和第三方的這個.a庫一起放進項目。
2、添加依賴的開源庫
如果我們的源碼依賴一些開源庫,比如AFNetWorking,Mansory等,就需要将它們打包進來,不過這樣一來,容易給使用者帶來問題,比如開源庫的沖突,版本不相容等。
是以我的處理辦法是,隻添加這些開源庫的頭檔案,然後告訴使用者我們的靜态庫是依賴這些開源庫的,讓他們自己下載下傳相應的架構。這樣做的好處是,友善第三方使用者随意更新自己的開源庫而不用擔心會跟靜态庫中的開源庫引起沖突,而且就算使用者更新了開源庫的版本,也一般不會改變頭檔案裡面的接口(高版本總會相容低版本),是以不會影響我們的靜态庫。
3、暴露出相應的接口(頭檔案),供第三方使用
我們打包靜态庫肯定是要給人用的,是以需要暴露出設計好的頭檔案供别人使用。靜态工程裡需要編譯的所有源檔案都會包含在Compile Source中,如下圖所示:
而需要暴露出來的頭檔案添加在Copy Files選項中,如下圖所示:
到此為止基本上完成了打包的準備工作,下面開始編譯。
#四、編譯生成靜态庫
根據需要,如果要在模拟器下使用靜态庫,編譯時就選擇模拟器,在真機中使用,編譯時就選擇真機。
這裡我在模拟器和真機下分别運作了一次,得到兩個.a檔案,真機和模拟器:
一般将靜态庫給别人使用時,要同時給真機版和模拟器版,給兩個檔案肯定是不友善的,是以要把兩個版本合并為一個.a檔案,這樣不管真機還是模拟器,都可以運作。
打開終端,可以先檢視下.a庫支援的架構,輸入 lipo -info 靜态庫路徑,靜态庫路徑這裡直接把檔案拖進來就好。
很顯然,armv7和arm64表示32位和64位真機,i386和x86_64表示32位和64位模拟器(mac的架構)。下面使用指令将真機版和模拟器版本合并:
lipo -create 靜态庫路徑1 靜态庫路徑2 -output /Users/yangjie/Desktop/YJEChatSDK.a
最終得到需要的YJEChatSDK.a檔案。
#處理資源檔案(圖檔.png和Xib檔案)
*首先僅考慮圖檔
如果代碼中使用了一些圖檔資源,怎麼樣才能正确讀取這些圖檔呢?我的做法是(我不太清楚是不是還有其他辦法):在桌面建立一個檔案夾,将用到的所有圖檔放進去,然後把檔案夾的名字改為:檔案名稱.Bundle。比如我這裡就改為YJsdkBundle.Bundle。這樣在使用靜态庫時,直接将該Bundle檔案一起放進工程就可以了。
然而這樣還是不行的,因為靜态庫中的代碼依然找不到圖檔資源的路徑,是以還是不能正确加載。我們需要重新傳回代碼,在代碼中添加兩個宏定義:
define BUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"YJsdkBundle.Bundle"]
define YJImageNamed(imageName) ([UIImage imageNamed:[NSString stringWithFormat:@"%@/%@",BUNDLE_PATH,imageName]])
将所有加載圖檔的方法[UIImage imageNamed:]替換為我們定義的宏,比如我這裡是YJImageNamed(圖檔名稱),需要注意的是,圖檔名稱要跟Bundle檔案中圖檔名稱對應(字尾@2x或者@3x不用加)。我這裡的Bundle檔案内并沒有子檔案夾,是以宏定義中,stringWithFormat:@"%@/%@",BUNDLE_PATH,imageName這麼寫,如果你的Bundle檔案下還有子檔案夾,應該這麼寫:
stringWithFormat:@"%@/檔案夾名稱/%@",BUNDLE_PATH,imageName
這樣,圖檔就可以正确加載了!
關于Xib檔案
對于Xib檔案,我并沒有親自嘗試,是以。。。沒有發言權了,大家可以谷歌一下。(__*)
打包好之後,使用時編譯連接配接錯誤問題:
類似這種奇怪的錯誤,我遇到了,原因是,1、沒有引入必要的系統架構。2、靜态庫已經包含了某些檔案,使用的時候,又引入了這些檔案,造成duplicate錯誤。
連結:https://www.jianshu.com/p/bc00e1a06489
來源:簡書