標籤:
最近想把自己的一些工具 + 生產力類搞成一個靜態庫,網上搜了下關於framework和.a的一些相關資料,然而寫的或不全面,或不詳細,我歸納總結及親自實踐寫下這篇文章。由於篇幅原因多工程聯調見另一個部落格iOS 工程套子工程,主工程和framework工程或.a靜態庫工程聯調
一、framework和.a兩種靜態庫的介紹及區別
.a是一個純二進位檔案,.framework中除了有二進位檔案之外還有資源檔。
.a檔案不能直接使用,至少要有.h檔案配合,.framework檔案可以直接使用。
.a + .h + sourceFile = .framework。
.a只是靜態庫。framework既可以是靜態庫也可以是動態庫。例如系統的framework就是動態庫。
靜態庫:連結時完整地拷貝至可執行檔中,被多次使用就有多份冗餘拷貝。
動態庫:連結時不複製,程式運行時由系統動態載入到記憶體,供程式調用,系統只載入一次,多個程式共用,節省記憶體。
然而蘋果是不會讓開發人員有自己的動態庫的。
二、framework製作及使用
1.建立framework項目
2.加一些我們實用的類進來
3.檔案剛拉進來時如,只有APPBaseSDK.h是預設放在public中,我們還要把project中需要暴露給外面用的.h檔案移到public中去
4.然後設定編譯模式,開啟Xcode菜單Product--->Scheme--->Edit Scheme,改為release模式,因為最終打包是要用release模式
5.設定最低支援版本
6.設定編譯出的靜態庫包含的指令集
模擬器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64
真機:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64
如果Build Active Architecture Only設定為YES,那麼編譯出來的靜態庫就只包含當前裝置的指令集。
舉個例子:如果我們選擇iPhone 5模擬器編譯,則編譯出來的靜態庫只能用iPhone4s~5模擬器跑程式,用iPhone5s~6plus,則會報找不到x86_64的APPBaseSDK庫。
設定為NO,則會把所有指令集的都打包合并。因此靜態庫有個缺點就是靜態庫包比源碼大很多。
7.最後修改產生的Mach-O格式
8.編譯產生靜態庫
編譯時間,需要用模擬器和真機各編譯一次,這樣Products目錄下的APPBaseSDK.framework靜態庫才會變為黑色,右鍵show in Finder,可以進入Products目錄下。
9.合并靜態庫檔案
要讓真機和模擬器都可用該靜態庫,需要將兩種靜態庫合并。framework靜態庫合并的不是framework,而是framework下的一個二進位檔案,即中標記的待合并檔案。lipo -create 第一個framework下二進位檔案的絕對路徑 第二個framework下二進位檔案的絕對路徑 -output 最終產生合并的二進位檔案路徑(我把它放案頭上)。
開啟終端使用的命令如下:
lipo -create /Users/zhanglinfeng/Library/Developer/Xcode/DerivedData/APPBaseSDK-dpqdspcdgwsrxgdihiaxpqpkvali/Build/Products/Release-iphoneos/APPBaseSDK.framework/APPBaseSDK /Users/zhanglinfeng/Library/Developer/Xcode/DerivedData/APPBaseSDK-dpqdspcdgwsrxgdihiaxpqpkvali/Build/Products/Release-iphonesimulator/APPBaseSDK.framework/APPBaseSDK -output /Users/zhanglinfeng/Desktop/APPBaseSDK
如果覺得敲檔案路徑好麻煩,可以將該檔案拖入終端即鍵入了該檔案的路徑。如果報錯建議將中Release-iphoneos和Release-iphonesimulator中的APPBaseSDK.framework刪掉,重新用模擬器和真機分別編譯一次再試。
真機的或者模擬器中隨便選一個framework,將該framework中的二進位檔案APPBaseSDK(也就是中待合并的檔案)替換成剛剛合并的檔案(剛產生在案頭上的)。好了,此framework就是我們需要的。
10.使用framework
將framework拖入建立的一個UseFrameworkTest工程,我這裡拖到箭頭所指的UseFrameworkTest檔案夾目錄下,如果你要拖到其他目錄,就要改Framework Search Paths,後面我會介紹Search Paths路徑相關知識
將framework中比較常用的標頭檔import到APPBaseSDK.h中(如畫圈的),這樣在外面只需要#import <APPBaseSDK/APPBaseSDK.h>,就可以引用到中畫圈的檔案。如果不想將太多檔案都import到APPBaseSDK.h中,在外面就像這樣引用#import <APPBaseSDK/MBProgressHUD+Easy.h>(雖然能使用但會警示告,所以還是import到APPBaseSDK.h中吧)
使用代碼,如可以正常調用將漢字轉拼音方法並列印結果了
注意:如果要用到framework中的category方法,需要設定Other Linker Flags為-ObjC(注意大小寫,有些資料裡大小寫搞錯了坑死我了)。引入了-ObjC標誌,它的作用就是將靜態庫中所有的和對象相關的檔案都載入進來本來這樣就可以解決問題了,不過在64位的Mac系統或者iOS系統下,連結器有一個 bug,會導致只包含有類別的靜態庫無法使用-ObjC標誌來負載檔案。變通方法是使用-all_load 或者-force_load標誌,它們的作用都是載入靜態庫中所有檔案,不過all_load作用於所有的庫,而-force_load後面必須要指定具 體的檔案。
三、.a靜態庫的製作及使用
1.建立靜態庫工程,工程命名為BaseSDK,產生的.a檔案名稱變成libBaseSDK。
2.刪掉自動產生的檔案BaseSDK.h BaseSDK.m
3.添加你的實用類檔案
4.添加Headers Phase
5.將暴露給外面用的標頭檔加入進來,加進來後要移到public中去(不移到public中也沒錯,只是下面第11步中不會出現.h檔案,需要從庫的源碼中找)
6.然後設定編譯模式,開啟Xcode菜單Product--->Scheme--->Edit Scheme,改為release模式,因為最終打包是要用release模式
7.設定Build Active Architecture Only
模擬器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64
真機:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64
如果Build Active Architecture Only設定為YES,那麼編譯出來的.a靜態庫就只包含當前裝置的指令集。
舉個例子:如果我們選擇iPhone 5模擬器編譯,則編譯出來的.a靜態庫只能用iPhone4s~5模擬器跑程式,用iPhone5s~6plus,則會報找不到x86_64的APPBaseSDK庫。
設定為NO,則會把所有指令集的都打包合并。因此靜態庫有個缺點就是靜態庫包比源碼大很多。
8.設定最低支援版本
9.編譯產生靜態庫
編譯時間,需要用模擬器和真機各編譯一次,這樣Products目錄下的libBaseSDK.a靜態庫才會變為黑色,右鍵show in Finder,可以進入Products目錄下。
10.合并模擬器和真機靜態庫檔案libBaseSDK.a,開啟終端命令如下
lipo -create /Users/zhanglinfeng/Library/Developer/Xcode/DerivedData/BaseSDK-cexmrzesjuswutaldkedwjpnpxnk/Build/Products/Release-iphoneos/libBaseSDK.a /Users/zhanglinfeng/Library/Developer/Xcode/DerivedData/BaseSDK-cexmrzesjuswutaldkedwjpnpxnk/Build/Products/Release-iphonesimulator/libBaseSDK.a -output /Users/zhanglinfeng/Desktop/libBaseSDK.a
11.使用.a靜態庫
將靜態庫拖入建立的工程,我這裡拖到箭頭所指的UseA檔案夾下(如果你要拖到其他目錄,就要改Library Search Paths,後面我會介紹Search Paths路徑相關知識),再將暴露給外面用的.h檔案也拖入工程,
注意:如果沒有include裡的.h檔案.那就從庫的源碼中挑出一些需要暴露的.h檔案。
匯入標頭檔就可以使用了,如
注意:如果要用到靜態庫中的category方法,需要設定Other Linker Flags為-ObjC(注 意大小寫,有些資料裡大小寫搞錯了坑死我了)。引入了-ObjC標誌,它的作用就是將靜態庫中所有的和對象相關的檔案都載入進來本來這樣就可以解決問題 了,不過在64位的Mac系統或者iOS系統下,連結器有一個 bug,會導致只包含有類別的靜態庫無法使用-ObjC標誌來負載檔案。變通方法是使用-all_load 或者-force_load標誌,它們的作用都是載入靜態庫中所有檔案,不過all_load作用於所有的庫,而-force_load後面必須要指定具 體的檔案。
四、關於使用庫時Search Paths
也許有人會納悶不用設定search Paths嗎,如果你按照我的步驟把靜態庫拖到工程的相應目錄,那就預設設定就可以了。
如果你把靜態庫放到你喜歡的路徑,就要根據靜態庫在檔案夾中的位置設定這個search Paths了。
標明了檔案夾路徑
“./”和“$(PROJECT_DIR)”表示當前工程所在檔案夾,是一個相對路徑,相對該工程在電腦的位置,會自動定位到在當前電腦的絕對路徑。如果寫絕對路徑,工程換了檔案夾位置,或換到其他電腦,路徑就報錯。“../”表示當前工程所在檔案夾的上一層檔案夾路徑。設定路徑時兩個參數的意義,non-recursive非遞迴尋找,recursive 遞迴尋找 。Search Paths具體例子我另一個部落格有iOS 工程套子工程,主工程和framework工程或.a靜態庫工程聯調
iOS 最新framework和.a靜態庫製作及使用全解