一、前言
“隔著一段距離看畔师,很多有趣的知識(shí)看起來(lái)都很唬人娶靡。”在我初出茅廬的時(shí)候著實(shí)覺(jué)得那些后綴名為“.frameworke”看锉、“.a”姿锭、“.dylib”的文件很神秘,很高冷伯铣。那時(shí)我雖然知道只要導(dǎo)入一個(gè)庫(kù)就能引用庫(kù)里面很多封裝好的東西呻此,但對(duì)這個(gè)“庫(kù)”究竟是什么“鬼”,一直都是云里霧里腔寡。后來(lái)開(kāi)發(fā)中有打包的需求焚鲜,然后就去找了些文章,但是都不是太全面放前,而且自己操作中有些小細(xì)節(jié)的地方也是挺坑的忿磅,就想寫(xiě)下自己打包過(guò)程中遇到的細(xì)節(jié)和坑,希望對(duì)你們有幫助犀斋。好了廢話不多說(shuō)贝乎,看下去就知道它是個(gè)什么“鬼”。
二 叽粹、一些概念的補(bǔ)充
1览效、 什么是庫(kù)?
所謂庫(kù)就是程序代碼的集合虫几,是共享程序代碼的一種方式锤灿。
2、 庫(kù)的分類
根據(jù)程序代碼的開(kāi)源情況辆脸,庫(kù)可以分為兩類
開(kāi)源庫(kù)
源代碼是公開(kāi)的但校,你可以看到具體實(shí)現(xiàn)。比如GitHub上比較出名的第三方框架AFNetworking啡氢、SDWebImage状囱。
閉源庫(kù)
不公開(kāi)源代碼术裸,只公開(kāi)調(diào)用的接口,看不到具體的實(shí)現(xiàn)亭枷,是一個(gè)編譯后的二進(jìn)制文件袭艺。這種常見(jiàn)于一些公司的SDK包,比如高德地圖SDK叨粘、環(huán)信即時(shí)通訊SDK等等猾编。而閉源庫(kù)又分為兩類:靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)。本篇重點(diǎn)要講的便是其中的靜態(tài)庫(kù)升敲。
3答倡、靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的存在形式和使用區(qū)別
存在形式:
靜態(tài)庫(kù)
以".a"或者“.framework”為文件后綴名
動(dòng)態(tài)庫(kù)
以".dylib"或者“.framework”為文件后綴名
使用區(qū)別:
靜態(tài)庫(kù)鏈接時(shí)會(huì)被完整的復(fù)制到可執(zhí)行文件中,被多次使用就有多份拷貝驴党。
靜態(tài)庫(kù)被程序使用時(shí)
動(dòng)態(tài)庫(kù)鏈接時(shí)不復(fù)制瘪撇,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存,供程序調(diào)用鼻弧。而且系統(tǒng)只加載一次设江,多個(gè)程序共用,節(jié)省內(nèi)存攘轩。
4、iOS 設(shè)備的CPU架構(gòu)
模擬器:
4s-5: i386
5s-7 Plus: x86_64
真機(jī)(iOS設(shè)備):
armv6: iPhone码俩、iPhone 2度帮、iPhone 3G、iPod Touch(第一代)稿存、iPod Touch(第二代)
armv7: iPhone 3Gs笨篷、iPhone 4、iPhone 4s瓣履、iPad率翅、iPad 2
armv7s: iPhone 5、iPhone 5c (靜態(tài)庫(kù)只要支持了armv7,就可以在armv7s的架構(gòu)上運(yùn)行)
arm64: iPhone 5s袖迎、iPhone 6冕臭、iPhone 6 Plus、iPhone 6s燕锥、iPhone 6s Plus辜贵、iPad Air、iPad Air2归形、iPad mini2托慨、iPad mini3
注:真機(jī)iPhone7、iPhone7 Plus A10處理器到底是什么架構(gòu)暫時(shí)不得而知暇榴,沒(méi)查到相關(guān)資料厚棵,貌似還沒(méi)公布蕉世,但是模擬器是x86_64。
5婆硬、a與.framework有什么區(qū)別狠轻?
.a是一個(gè)純二進(jìn)制文件,.framework中除了有二進(jìn)制文件之外還有資源文件柿祈。
.a文件不能直接使用哈误,至少要有.h文件配合,.framework文件可以直接使用躏嚎。
.a + .h + sourceFile = .framework蜜自。
建議用.framework.
6、制作靜態(tài)庫(kù)時(shí)的幾點(diǎn)注意:
1 注意理解:無(wú)論是.a靜態(tài)庫(kù)還.framework靜態(tài)庫(kù)卢佣,我們需要的都是二進(jìn)制文件+.h+其它資源文件的形式重荠,不同的是,.a本身就是二進(jìn)制文件虚茶,需要我們自己配上.h和其它文件才能使用戈鲁,而.framework本身已經(jīng)包含了.h和其它文件,可以直接使用嘹叫。
2 圖片資源的處理:兩種靜態(tài)庫(kù)婆殿,一般都是把圖片文件單獨(dú)的放在一個(gè).bundle文件中,一般.bundle的名字和.a或.framework的名字相同罩扇。.bundle文件很好弄婆芦,新建一個(gè)文件夾,把它改名為.bundle就可以了喂饥,右鍵消约,顯示包內(nèi)容可以向其中添加圖片資源。
3 category是我們實(shí)際開(kāi)發(fā)項(xiàng)目中經(jīng)常用到的员帮,把category打成靜態(tài)庫(kù)是沒(méi)有問(wèn)題的或粮,但是在用這個(gè)靜態(tài)庫(kù)的工程中,調(diào)用category中的方法時(shí)會(huì)有找不到該方法的運(yùn)行時(shí)錯(cuò)誤(selector not recognized)捞高,解決辦法是:在使用靜態(tài)庫(kù)的工程中配置other linker flags的值為-ObjC氯材。
4 如果一個(gè)靜態(tài)庫(kù)很復(fù)雜,需要暴露的.h比較多的話棠枉,就可以在靜態(tài)庫(kù)的內(nèi)部創(chuàng)建一個(gè).h文件(一般這個(gè).h文件的名字和靜態(tài)庫(kù)的名字相同)浓体,然后把所有需要暴露出來(lái)的.h文件都集中放在這個(gè).h文件中,而那些原本需要暴露的.h都不需要再暴露了辈讶,只需要把.h暴露出來(lái)就可以了命浴。
三、進(jìn)入主題:打包靜態(tài)庫(kù)!
.a文件靜態(tài)庫(kù)打包
1生闲、打開(kāi)Xcode創(chuàng)建一個(gè)新的工程媳溺,這里以Xcode8為例,選擇工程如下:
2碍讯、創(chuàng)建工程完畢后悬蔽,界面如下(以打包SDWebImage為例)
系統(tǒng)會(huì)默認(rèn)幫我們生成兩個(gè)文件,可以只留一個(gè).h文件然后把SDWebImage框架的所有文件拖拽到工程里面捉兴,然后把想暴露的頭文件寫(xiě)在SDWebImage.h里面(也可以倆個(gè)文件都刪除蝎困,把框架的文件都拖拽進(jìn)去)。
我們知道靜態(tài)庫(kù)存在的最大意義是隱藏代碼的具體實(shí)現(xiàn)倍啥,但是這也隱藏的太徹底了禾乘,總要公開(kāi)些接口或者頭文件供人調(diào)用吧。
3虽缕、公開(kāi)接口頭文件
targets->Build Phases->Copy Files->"+"你需要公開(kāi)的頭文件
選擇需要對(duì)外公開(kāi)的.h(建議添加所有的.h始藕,如果你只想對(duì)外提供部分的.h,要保證這些.h里面沒(méi)有導(dǎo)入其他未添加到Copy Files的.h氮趋,否則你在編譯后生成的.a在使用的時(shí)候就會(huì)報(bào)錯(cuò))輸入.h伍派,然后command+a 全選,點(diǎn)擊Add
4剩胁、設(shè)置適配所有架構(gòu)
project -> buildSeting -> Build Active Architecture Only 設(shè)為NO
5诉植、運(yùn)行工程進(jìn)行打包
command + b 編譯就會(huì)生成靜態(tài)庫(kù)了,
Debug-iphoneos 這個(gè)就是Debug模式的真機(jī)靜態(tài)庫(kù)昵观,
可以通過(guò)選擇Run的info設(shè)置 Debug 和 Release倍踪,設(shè)置Debug和Release。
通過(guò)選擇Generic iOS Device 和 模擬器索昂,設(shè)置真機(jī)和模擬器。
所以你會(huì)得到四種靜態(tài)庫(kù):
Debug-iphoneos ? ? ?Debug-iphonesimulator
Release-iphoneos ? ? ?Release-iphonesimulator
6扩借、終端查看靜態(tài)庫(kù)所支持的架構(gòu)
終端->cd進(jìn)入庫(kù)文件路徑(Debug-iphoneos這個(gè)目錄下面)->lipo -info 庫(kù)名(lipo -info libSDWebImage.a) ? ? ? ? ? ? ? ? ? ? ? ? 文件的路徑:可以通過(guò)直接拖拽文件到終端
或者 ? ? ?終端->lipo -info .a的路徑
可以看到支持 armv7 arm64(靜態(tài)庫(kù)只要支持了armv7,就可以在armv7s的架構(gòu)上運(yùn)行)
如果不設(shè)置第4步:project -> buildSeting -> Build Active Architecture Only 設(shè)為NO椒惨,生成的靜態(tài)庫(kù)只會(huì)支持當(dāng)前選擇的模擬器或者真機(jī)的架構(gòu)。
7.合并真機(jī)和模擬器的靜態(tài)庫(kù)
進(jìn)入電腦的終端命令,進(jìn)入到product的目錄文件下,執(zhí)行命令cd+product的文件路徑
lipo -create 靜態(tài)庫(kù)1路徑 靜態(tài)庫(kù)2路徑 -output 合并的靜態(tài)庫(kù)名字(libSDWebImage.a)
lipo -info 靜態(tài)庫(kù)路徑 ?查看靜態(tài)庫(kù)支持的架構(gòu)潮罪,可以看到能夠支持所有的架構(gòu)了康谆。
看了好多文章有說(shuō)Debug和Release也能合并,但是沒(méi)搞出來(lái)嫉到,有成功的麻煩也告知下我沃暗。
.frameworke文件靜態(tài)庫(kù)打包
1、依然Xcode創(chuàng)建一個(gè)新的工程FrameworkeLib,選擇工程如下:(以打包MJRefresh為例)
2、創(chuàng)建完成后我們可以看到剂习,工程本身自帶一個(gè)MJRefreshFramework.h文件勺馆,這是類似一個(gè)主頭文件一樣的東西誉己。
然后把SDWebImage框架的所有文件拖拽到工程里面涕刚。
這里將MJRefresh.h刪除了(不需要了)几晤,需要暴露的頭文件寫(xiě)在MJRefreshFramework.h里面宫补,以這樣的形式#import
3盛撑、設(shè)置支持所有模擬器架構(gòu)或真機(jī)架構(gòu)(和打包.a第4步驟一樣)
4碎节、公開(kāi)頭文件
target-Build Phases - Headers -把需要公開(kāi)的頭文件從project拖入Public 或者右鍵Move to public Group(這里將全部頭文件添加進(jìn)去,根據(jù)需求添加想要暴露的.h抵卫,不要出現(xiàn)Public里的.h有import Project里的.h狮荔,被坑過(guò))
5、設(shè)置打包的是靜態(tài)庫(kù)介粘。因?yàn)閯?dòng)態(tài)庫(kù)也可以是以framework形式存在殖氏,所以需要設(shè)置,否則默認(rèn)打出來(lái)的是動(dòng)態(tài)庫(kù)
target->BuildSetting ->搜索關(guān)鍵字mach->Mach-o Type 設(shè)為Static Library(這個(gè)默認(rèn)選項(xiàng)是動(dòng)態(tài)的)
6碗短、選中真機(jī)(可以選擇手機(jī)或者Generic iOS Device)或模擬器運(yùn)行設(shè)備打包(與打包.a一樣command + b)受葛,完成后Products文件夾下的MJRefreshFramework.framework文件由紅色變成了黑色,右鍵show in finder
合并和查看靜態(tài)庫(kù)支持的架構(gòu)和上面一樣 ??
四偎谁、使用靜態(tài)庫(kù)?
使用的時(shí)候把合并的靜態(tài)庫(kù)拖拽到工程即可(如果有資源文件如bundle总滩,還需要手動(dòng)添加進(jìn)去,系統(tǒng)不默認(rèn)添加)
還有最近剛出xcode9試了下巡雨,好像編譯打包在Products下面是沒(méi)有靜態(tài)庫(kù)的闰渔,只好用xcode8了,還有如果用xcode9打開(kāi)的項(xiàng)目铐望,你在拖拽打包好的靜態(tài)庫(kù)到工程里面后Targets->select?you?target-->Build?Phases->Link?Binary?With?Libraries里面不會(huì)自動(dòng)添加靜態(tài)庫(kù)冈涧,需要手動(dòng)添加(很扯淡)
END