轉載鏈接 http://www.cnblogs.com/yinxiao-bai1014/p/5670420.html
庫介紹
庫從本質上來說是一種可執(zhí)行代碼的二進制格式匪煌,可以被載入內(nèi)存中執(zhí)行。庫分靜態(tài)庫和動態(tài)庫兩種党巾。
iOS中的靜態(tài)庫有 .a 和 .framework兩種形式萎庭;動態(tài)庫有.dylib 和 .framework 形式,后來.dylib動態(tài)庫又被蘋果替換成.tbd的形式齿拂。
靜態(tài)庫與動態(tài)庫的區(qū)別
靜態(tài)庫和動態(tài)庫是相對編譯期和運行期的:靜態(tài)庫在程序編譯時會被鏈接到目標代碼中驳规,程序運行時將不再需要改靜態(tài)庫;而動態(tài)庫在程序編譯時并不會被鏈接到目標代碼中署海,只是在程序運行時才被載入达舒,因為在程序運行期間還需要動態(tài)庫的存在。
總結:同一個靜態(tài)庫在不同程序中使用時叹侄,每一個程序中都得導入一次,打包時也被打包進去昨登,形成一個程序趾代。而動態(tài)庫在不同程序中,打包時并沒有被打包進去丰辣,只在程序運行使用時撒强,才鏈接載入(如系統(tǒng)的框架如UIKit、Foundation等)笙什,所以程序體積會小很多飘哨,但是蘋果不讓使用自己的動態(tài)庫,否則審核就無法通過琐凭。
創(chuàng)建.a靜態(tài)庫
第一步芽隆,新建工程。一般使用工程名就使用庫的名稱,比如我這里用FMDB來創(chuàng)建靜態(tài)庫胚吁,我的工程名就取名為FMDB牙躺,創(chuàng)建的.a靜態(tài)庫就是libFMDB.a。
第二步腕扶,刪除系統(tǒng)默認創(chuàng)建的【FMDB.h】和【FMDB.m】文件孽拷,導入需要打包的源文件。
第三步(方式一)半抱,修改項目配置
點擊上圖中的【3】脓恕,彈出的列表中選擇【New Headers Phase】,打開【Headers (0 items)】,點擊左下角的【+】窿侈,選擇所有的.h文件炼幔。
第三步(方式二),修改項目配置
第四步棉磨,修改導出product配置
第五步江掩,修改編譯指令集
模擬器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64
真機:iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64
如果第五步這里,設置為YES乘瓤,那么編譯出來的.a靜態(tài)庫就只包含當前設備的指令集环形。
舉個例子:如果我們選擇iPhone 5模擬器【Command+B】編譯,則編譯出來的.a靜態(tài)庫只能用iPhone4s~5模擬器跑程序衙傀,用iPhone5s~6plus抬吟,則會報找不到x86_64的libFMDB庫。
設置為NO统抬,則會把所有指令集的都打包合并火本。
第六步,編譯(快捷鍵【Command+B】
編譯時聪建,需要用模擬器和真機各編譯一次钙畔,這樣Products目錄下的libFMDB.a靜態(tài)庫才會變?yōu)楹谏益Ishow in Finder金麸,可以進入Products目錄下擎析。
為什么需要用模擬器和真機各編譯一次呢?
可以看到Products目錄下有【Release-iphoneos】和【Release-iphonesimulator】兩個文件件挥下。前者里面是真機使用的.a靜態(tài)庫揍魂,后者是模擬器使用的.a靜態(tài)庫。
注意:如果步驟四中棚瘟,不將Build Configuration改為Release,則打包出來的靜態(tài)庫會存于【Debug-iphoneos】和【Debug-iphonesimulator】兩個文件夾下现斋。
我們一般都使用Release模式,因為程序最終發(fā)布之后是Release版的偎蘸,所以靜態(tài)庫也是在Release模式下使用庄蹋。
如果想要通用需要將模擬器使用的靜態(tài)庫與真機使用的靜態(tài)庫合并成一個靜態(tài)庫瞬内,可以使用終端命令來實現(xiàn)。命令格式:
lipo -create 第一個.a文件的絕對路徑 第二個.a文件的絕對路徑 -output 最終的.a文件路徑蔓肯。
本文中使用的命令如下:
lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphoneos/libFMDB.a /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-ctegiztcjikewoeprxxtmryzetfa/Build/Products/Release-iphonesimulator/libFMDB.a -output /Users/harvey/Desktop/libFMDB.a
補充:經(jīng)過多次實踐遂鹊,第三步的操作省略,依然可以導出可正常使用的包蔗包。
如果靜態(tài)庫中有category類秉扑,則在使用靜態(tài)庫的項目配置中【Other Linker Flags】需要添加參數(shù)【-ObjC]或者【-all_load】。
創(chuàng)建framework靜態(tài)庫
第一步调限,新建項目
第二步舟陆,刪除系統(tǒng)默認創(chuàng)建的【FMDB.h】和【FMDB.m】文件,導入需要打包的源文件耻矮。
第三步秦躯,修改項目配置
首先,設置需要暴漏的頭文件
這里需要注意的是暴露出來的頭文件中import的其他類也得添加到public中暴露出來裆装。
如果不想將import的類暴露出來踱承,那么在頭文件中用@class 然后在對應的.m文件中再import。
然后設置編譯模式哨免,在Xcode菜單【Product】--->【Scheme】--->【Edit Scheme...】中
設置編譯出的靜態(tài)庫包含的指令集
最后修改生成的Mach-O格式
第四步茎活,編譯生成靜態(tài)庫
編譯時,需要用模擬器和真機各編譯一次琢唾,這樣Products目錄下的libFMDB.a靜態(tài)庫才會變?yōu)楹谏乩螅益Ishow in Finder,可以進入Products目錄下采桃。
第五步懒熙,合并模擬器版framework和真機版framework
合并的命令同上面相似,不同之處是:framework靜態(tài)庫合并的不是framework,而是framework下的一個二進制文件普办,即上一步圖中標記的文件工扎。
lipo -create 第一個framework下二進制文件的絕對路徑 第二個framework下二進制文件的絕對路徑 -output 最終的二進制文件路徑。
本文中使用的命令如下:
1
lipo -create /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphonesimulator/FMDB.framework/FMDB /Users/harvey/Library/Developer/Xcode/DerivedData/FMDB-clvayfrjgytqrbdkyqrtcjkxfeuz/Build/Products/Release-iphoneos/Release-iphoneos.framework/FMDB -output /Users/harvey/Desktop/FMDB
最后將任何一個framework中的二進制文件替換成合并后的二進制文件即可衔蹲。
把framework添加到要使用的項目中即可使用定庵。
注意:如果創(chuàng)建的framework中使用了category類,則在使用framework的項目配置中【Other Linker Flags】需要添加參數(shù)【-ObjC]或者【-all_load】踪危。
如果使用framework的使用出現(xiàn)【Umbrella header for module 'XXXX' does not include header 'XXXXX.h'】,是因為錯把xxxxx.h拖到了public中。
如果出現(xiàn)【dyld: Library not loaded:XXXXXX】猪落,是因為打包的framework版本太高贞远。比如打包framework時,選擇的是iOS 9.0笨忌,而實際的工程環(huán)境是iOS 8開始的蓝仲。
如果創(chuàng)建的framework類中使用了.dylib或者.tbd,首先需要在實際項目中導入.dylib或者.tbd動態(tài)庫,然后需要設置【Allow Non-modular Includes ....】為YES袱结,否則會報錯"Include of non-modular header inside framework module"亮隙。
補充:打包成的靜態(tài)庫肯定是比源碼類要大很多的,因為是由不同指令集不同設備的版本合并成的垢夹。所以如果你很在意你的app大小,并且也不是很需要打包成靜態(tài)庫的話果元,還是用原始類吧促王。
framework靜態(tài)庫中是可以包含圖片資源的;而.a靜態(tài)庫中不能包含圖片資源而晒,只能另外創(chuàng)建一個目錄存放蝇狼。
填坑記錄
上面的注意里提到了一些坑,以及解決辦法倡怎。這里再記錄一些:
1.framework中用到了NSClassFromString迅耘,但是轉換出來的class 一直為nil。
先來看一下這個API的官方描述
什么意思呢监署?如果轉換出來的class為nil颤专,有兩種情況:一種情況是這個類不存在;第二種情況是這個類還沒有被load焦匈。所以一般出現(xiàn)問題血公,都是第二種情況。
怎么解決這個問題呢缓熟?在主工程的【Other Linker Flags】需要添加參數(shù)【-ObjC]即可累魔。