Xcode 創(chuàng)建.a和framework靜態(tài)庫(kù)

iOS中的靜態(tài)庫(kù)有 .a 和 .framework兩種形式;動(dòng)態(tài)庫(kù)有.dylib 和 .framework 形式,后來(lái).dylib動(dòng)態(tài)庫(kù)又被蘋(píng)果替換成.tbd的形式。
靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的區(qū)別
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)是相對(duì)編譯期和運(yùn)行期的:靜態(tài)庫(kù)在程序編譯時(shí)會(huì)被鏈接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要改靜態(tài)庫(kù);而動(dòng)態(tài)庫(kù)在程序編譯時(shí)并不會(huì)被鏈接到目標(biāo)代碼中,只是在程序運(yùn)行時(shí)才被載入,因?yàn)樵诔绦蜻\(yùn)行期間還需要?jiǎng)討B(tài)庫(kù)的存在。總結(jié):同一個(gè)靜態(tài)庫(kù)在不同程序中使用時(shí),每一個(gè)程序中都得導(dǎo)入一次,打包時(shí)也被打包進(jìn)去,形成一個(gè)程序。而動(dòng)態(tài)庫(kù)在不同程序中,打包時(shí)并沒(méi)有被打包進(jìn)去,只在程序運(yùn)行使用時(shí),才鏈接載入(如系統(tǒng)的框架如UIKit、Foundation等),所以程序體積會(huì)小很多,但是蘋(píng)果不讓使用自己的動(dòng)態(tài)庫(kù),否則審核就無(wú)法通過(guò)。
創(chuàng)建.a靜態(tài)庫(kù)
第一步,新建工程。一般使用工程名就使用庫(kù)的名稱(chēng),比如我這里用FMDB來(lái)創(chuàng)建靜態(tài)庫(kù),我的工程名就取名為FMDB,創(chuàng)建的.a靜態(tài)庫(kù)就是libFMDB.a。


使用靜態(tài)庫(kù)模板新建工程.png

創(chuàng)建的工程.png

第二步,刪除系統(tǒng)默認(rèn)創(chuàng)建的【FMDB.h】和【FMDB.m】文件,導(dǎo)入需要打包的源文件。


導(dǎo)入源文件后.png

第三步(方式一),修改項(xiàng)目配置


修改配置.png

點(diǎn)擊上圖中的【3】,彈出的列表中選擇【New Headers Phase】,打開(kāi)【Headers (0 items)】,點(diǎn)擊左下角的【+】,選擇所有的.h文件。


配置需要暴漏的文件的.h頭.png

第三步(方式二),修改項(xiàng)目配置


修改項(xiàng)目配置.png

第四步,修改導(dǎo)出product配置


修改編譯配置.png

第五步,修改編譯指令集


設(shè)置Release為NO.png

模擬器:iPhone4s~5 : i386 iPhone5s~6plus : x86_64真機(jī):iPhone3gs~4s : armv7 iPhone5~5c : armv7s iPhone5s~6plus : arm64如果第五步這里,設(shè)置為YES,那么編譯出來(lái)的.a靜態(tài)庫(kù)就只包含當(dāng)前設(shè)備的指令集。舉個(gè)例子:如果我們選擇iPhone 5模擬器【Command+B】編譯,則編譯出來(lái)的.a靜態(tài)庫(kù)只能用iPhone4s5模擬器跑程序,用iPhone5s6plus,則會(huì)報(bào)找不到x86_64的libFMDB庫(kù)。設(shè)置為NO,則會(huì)把所有指令集的都打包合并。
第六步,編譯(快捷鍵【Command+B】編譯時(shí),需要用模擬器和真機(jī)各編譯一次,這樣Products目錄下的libFMDB.a靜態(tài)庫(kù)才會(huì)變?yōu)楹谏益Ishow in Finder,可以進(jìn)入Products目錄下。

小范筆記:(如果想要要.a文件生成在本工程指定的目錄下,需要將PROJECT-Build Settings-Per-configuration Build Products Path 目錄改成$(SRCROOT)/LibraryDemo/Library就可以("$(SRCROOT)/當(dāng)前工程名字/需要包含頭文件所在文件夾"))


編譯結(jié)果.png

為什么需要用模擬器和真機(jī)各編譯一次呢?可以看到Products目錄下有【Release-iphoneos】和【Release-iphonesimulator】?jī)蓚€(gè)文件件。前者里面是真機(jī)使用的.a靜態(tài)庫(kù),后者是模擬器使用的.a靜態(tài)庫(kù)。
注意:如果步驟四中,不將Build Configuration改為Release,則打包出來(lái)的靜態(tài)庫(kù)會(huì)存于【Debug-iphoneos】和【Debug-iphonesimulator】?jī)蓚€(gè)文件夾下。我們一般都使用Release模式,因?yàn)槌绦蜃罱K發(fā)布之后是Release版的,所以靜態(tài)庫(kù)也是在Release模式下使用。

如果想要通用需要將模擬器使用的靜態(tài)庫(kù)與真機(jī)使用的靜態(tài)庫(kù)合并成一個(gè)靜態(tài)庫(kù),可以使用終端命令來(lái)實(shí)現(xiàn)。命令格式:lipo -create 第一個(gè).a文件的絕對(duì)路徑 第二個(gè).a文件的絕對(duì)路徑 -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

補(bǔ)充:經(jīng)過(guò)多次實(shí)踐,第三步的操作省略,依然可以導(dǎo)出可正常使用的包。如果靜態(tài)庫(kù)中有category類(lèi),則在使用靜態(tài)庫(kù)的項(xiàng)目配置中【Other Linker Flags】需要添加參數(shù)【-ObjC]或者【-all_load】。

創(chuàng)建framework靜態(tài)庫(kù)
第一步,新建項(xiàng)目


新建項(xiàng)目.png

第二步,刪除系統(tǒng)默認(rèn)創(chuàng)建的【FMDB.h】和【FMDB.m】文件,導(dǎo)入需要打包的源文件。


導(dǎo)入源碼后的工程.png

第三步,修改項(xiàng)目配置首先,設(shè)置需要暴漏的頭文件


header文件設(shè)置.png

這里需要注意的是暴露出來(lái)的頭文件中import的其他類(lèi)也得添加到public中暴露出來(lái)。如果不想將import的類(lèi)暴露出來(lái),那么在頭文件中用@class 然后在對(duì)應(yīng)的.m文件中再import。

然后設(shè)置編譯模式,在Xcode菜單【Product】--->【Scheme】--->【Edit Scheme...】中


設(shè)置編譯模式.png

設(shè)置編譯出的靜態(tài)庫(kù)包含的指令集


設(shè)置編譯出的靜態(tài)庫(kù)包含的指令集.png

最后修改生成的Mach-O格式


修改Mach-O 格式.png

第四步,編譯生成靜態(tài)庫(kù)編譯時(shí),需要用模擬器和真機(jī)各編譯一次,這樣Products目錄下的libFMDB.a靜態(tài)庫(kù)才會(huì)變?yōu)楹谏益Ishow in Finder,可以進(jìn)入Products目錄下。


編譯生成的framework靜態(tài)庫(kù).png

第五步,合并模擬器版framework和真機(jī)版framework合并的命令同上面相似,不同之處是:framework靜態(tài)庫(kù)合并的不是framework,而是framework下的一個(gè)二進(jìn)制文件,即上一步圖中標(biāo)記的文件。lipo -create 第一個(gè)framework下二進(jìn)制文件的絕對(duì)路徑 第二個(gè)framework下二進(jìn)制文件的絕對(duì)路徑 -output 最終的二進(jìn)制文件路徑。本文中使用的命令如下:
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

最后將任何一個(gè)framework中的二進(jìn)制文件替換成合并后的二進(jìn)制文件即可。把framework添加到要使用的項(xiàng)目中即可使用。
注意:如果創(chuàng)建的framework中使用了category類(lèi),則在使用framework的項(xiàng)目配置中【Other Linker Flags】需要添加參數(shù)【-ObjC]或者【-all_load】。如果使用framework的使用出現(xiàn)【Umbrella header for module 'XXXX' does not include header 'XXXXX.h'】,是因?yàn)殄e(cuò)把xxxxx.h拖到了public中。如果出現(xiàn)【dyld: Library not loaded:XXXXXX】,是因?yàn)榇虬膄ramework版本太高。比如打包framework時(shí),選擇的是iOS 9.0,而實(shí)際的工程環(huán)境是iOS 8開(kāi)始的。

如果創(chuàng)建的framework類(lèi)中使用了.dylib或者.tbd,首先需要在實(shí)際項(xiàng)目中導(dǎo)入.dylib或者.tbd動(dòng)態(tài)庫(kù),然后需要設(shè)置【Allow Non-modular Includes ....】為YES,否則會(huì)報(bào)錯(cuò)"Include of non-modular header inside framework module"。


設(shè)置【Allow Non-modular Includes ....】.png

補(bǔ)充:打包成的靜態(tài)庫(kù)肯定是比源碼類(lèi)要大很多的,因?yàn)槭怯刹煌噶罴煌O(shè)備的版本合并成的。所以如果你很在意你的app大小,并且也不是很需要打包成靜態(tài)庫(kù)的話(huà),還是用原始類(lèi)吧。framework靜態(tài)庫(kù)中是可以包含圖片資源的;而.a靜態(tài)庫(kù)中不能包含圖片資源,只能另外創(chuàng)建一個(gè)目錄存放。

填坑記錄
上面的注意里提到了一些坑,以及解決辦法。這里再記錄一些:1.framework中用到了NSClassFromString
,但是轉(zhuǎn)換出來(lái)的class 一直為nil。先來(lái)看一下這個(gè)API的官方描述

官方描述.png

什么意思呢?如果轉(zhuǎn)換出來(lái)的class為nil,有兩種情況:一種情況是這個(gè)類(lèi)不存在;第二種情況是這個(gè)類(lèi)還沒(méi)有被load。所以一般出現(xiàn)問(wèn)題,都是第二種情況。怎么解決這個(gè)問(wèn)題呢?在主工程的【Other Linker Flags】需要添加參數(shù)【-ObjC]即可。
2.framework中把圖片、音頻打包進(jìn)bundle中,但是一直加載不到。打包的framework中有一個(gè)bundle,bundle里有一些圖片、音頻等資源。但是用如下方式:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"XXXX" ofType:@"bundle"];NSString *mp3Path = [[NSBundle bundleWithPath:bundlePath] pathForResource:@"Message_system" ofType:@"mp3"];

獲取的mp3Path一直為nil。framework,只暴露了一些.h頭文件,bundle沒(méi)有暴露出來(lái),無(wú)法獲取。那么我們只需要將bundle與framework一起放入目標(biāo)工程中即可。其實(shí)bundle根本不用打包進(jìn)framework中。例如:我們創(chuàng)建了一個(gè)叫ABC.framework的靜態(tài)庫(kù)。庫(kù)中使用了Message_system.mp3
,那么我們創(chuàng)建一個(gè)bundle,命名為ABC.bundle,然后將Message_system.mp3放入bundle中。打包的時(shí)候,framework并不包含ABC.bundle。最后在要使用ABC.framework的工程中,新建一個(gè)文件夾or group,然后把ABC.framework和ABC.bundle一起拖進(jìn)去,就可以啦。
Have Fun!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容