組件化模塊(四): 靜態(tài)庫的封裝

當(dāng)我們看好多第三方的插件的時(shí)候,會發(fā)現(xiàn)好多.a/.framework的靜態(tài)庫晦嵌,之所以這些大廠這么做,其實(shí)是為了方便在集成完畢之后拷姿,快速的編譯耍铜,最重要的是看不到自己的源碼,并且保護(hù)我們的代碼跌前。并且在MRC階段的代碼棕兼,如果想要在ARC下使用,那么確實(shí)需要進(jìn)行ARC兼容抵乓,但是我們進(jìn)行編譯之后伴挚,并不需要考慮這些問題,直接引用這個(gè)編譯好的靜態(tài)庫就行灾炭,并不需要兼容ARC茎芋,確實(shí)好處多多。

首先講解如何創(chuàng)建.a的二進(jìn)制文件

1.創(chuàng)建一個(gè)靜態(tài)庫工程

創(chuàng)建靜態(tài)庫

2.由于不同的模擬器以及真機(jī)對應(yīng)著不同的架構(gòu)蜈出,

模擬器:4-5:i386? ?5s-iphoneX:x86-64

真機(jī):3gs-4s: armv7(兼容7s)? ?5-5c: armv7s? ?5s-iphoneX:arm64

為了適配所有的CPU架構(gòu)我們設(shè)置如下田弥,Build Active Architecture Only? YES表示只編譯某些比較主流的架構(gòu),所以要想都進(jìn)行編譯铡原,我們需要對所有的都編譯

注意如果你用的是比較新的xcode版本,比如xcode10,那么由于并沒有自帶比較老的模擬器,比如4/4s等,那么生成出來的靜態(tài)庫架構(gòu)并不會包含i386或者armv7,如果想兼容4/4s等比較久的機(jī)型,需要下載老的模擬器版本

設(shè)置允許的架構(gòu)類型

3.查看生成的.a文件架構(gòu)架構(gòu)

在終端中cd 到.a文件的父文件

輸入命令 lipo? -info? 靜態(tài)庫名稱.a

輸出當(dāng)前所有支持的架構(gòu)

架構(gòu)類型

4.暴露.h 文件

暴露.h

5.默認(rèn)生成的.a文件模擬器和真機(jī)是分開的偷厦,所以需要合成同時(shí)支持真機(jī)和模擬器的.a

lipo -create 模擬器中.a文件地址 真機(jī)中.a文件地址 -output? 新的文件名.a

合成

6.生成realease版本的靜態(tài)庫(上面生成的是debug版本)

靜態(tài)庫

然后在項(xiàng)目中切換真機(jī)/模擬器,command+B燕刻,就會在.a文件的根目錄發(fā)現(xiàn)release/debug只泼、真機(jī)/模擬器版本信息

所有的.a文件

當(dāng)我們應(yīng)用.a文件的時(shí)候,只需要將import? .h文件進(jìn)來就可以直接使用靜態(tài)庫文件里的方法了卵洗。

接下來我們用framework來生成靜態(tài)庫

.a文件是一個(gè)純二進(jìn)制文件请唱,.frameWork中除了有二進(jìn)制文件還有其他的資源文件;.a文件必須有.h文件配合使用,frameWork文件可以直接使用十绑;framework靜態(tài)庫就類似一個(gè)文件夾聚至,所有的子類文件都要放到framework中,包括可執(zhí)行文件frameWork和.h以及資源文件本橙⊥砹耄可以這么總結(jié).a+.h+sourceFile(資源文件)=framework,所以相比.a文件來說,framework更加易于管理勋功,所以本人更傾向與生成framework靜態(tài)庫

同樣在新建工程中選擇

生成

2.項(xiàng)目中添加一個(gè)工具類Tool坦报,當(dāng)Command+B編譯之后,在framework中發(fā)現(xiàn)只有frameWork.h的頭文件,并沒有我們想要的Tool.h,所以我們需要對Tool.h暴露,將暴露到外界的.h文件放到public目錄下,如果不用frameWork.h主頭文件,可以將其刪除

暴露.h

3.檢查可執(zhí)行文件支持的CPU架構(gòu)

注意cd到.frameWork,然后檢查目錄下frameWork可執(zhí)行文件中的架構(gòu),發(fā)現(xiàn)是x86_64,由于當(dāng)前是在模擬器上進(jìn)行的編譯,所以我們需要兼容所有的模擬器/真機(jī)類型.

支持的種類

修改當(dāng)前active Architecture Only的類型為No,表示所有的模擬器/真機(jī)架構(gòu)都需要編譯

編譯架構(gòu)

接下來我們需要在XCode中選擇設(shè)備處設(shè)置為Generic ios Device,編譯后的結(jié)構(gòu)可以在項(xiàng)目中的Products->Framework.framework包中找到編譯之后的結(jié)構(gòu),包含真機(jī)和模擬器兩部分.

選擇設(shè)備


4.適配所有的CPU架構(gòu)(和上邊生成.a文件一樣)

5.生成release版本的.framework靜態(tài)庫,而不是debug版本的靜態(tài)庫注意:當(dāng)前5到7步是生成了動態(tài)庫狂鞋,可以直接看7步中的原因片择,進(jìn)行相應(yīng)的步驟調(diào)整。這樣寫是為了更好的記錄遇到的問題

6.合成適配模擬器和真機(jī)的靜態(tài)庫

注意合成的是靜態(tài)庫目錄下的可執(zhí)行文件(frameWork)的合并骚揍。

將地址拖過來就行

lipo -create 模擬器中可執(zhí)行文件地址 真機(jī)中可執(zhí)行文件地址 -output? 新的文件名.framework

將生成的frameWork字管,替換掉之前release版本里的可執(zhí)行文件,那么這個(gè)frameWork就可以用了信不。

7.修改frameWork(剛生成的時(shí)候其實(shí)為動態(tài)庫)為靜態(tài)庫

查看文件


引用framWork

防止崩潰的發(fā)生嘲叔,我們需要將frameWork動態(tài)庫引用進(jìn)Embedded Binaries

所以,當(dāng)我們生成frameWork的時(shí)候就應(yīng)該生成靜態(tài)庫抽活。所以在生成frameWork工程中硫戈,

修改framework類型為靜態(tài)庫

將Dynamic Library修改為 Static Library。所以上邊的第5到第7個(gè)步驟中我們需要重新進(jìn)行生成下硕。(刪除工程中Library Framework和 Embedded Binaries 中的動態(tài)庫文件)重新導(dǎo)入工程進(jìn)行測試丁逝,發(fā)現(xiàn)不將framework引入Embedded Binaries,也是可以正常運(yùn)行的梭姓,那么現(xiàn)在生成的是靜態(tài)庫了霜幼。

記錄一些問題:

(1).圖片資源的導(dǎo)入問題?(framework和.a圖片的導(dǎo)入方式是一樣的)

拿生成.a靜態(tài)庫舉例,添加資源文件,將圖片放入Tool.h同級目錄下,編譯,會發(fā)現(xiàn)我們編譯后的包中,并沒有我們的資源圖片,我們需要將圖片文件添加到BuildPhases->CopyFiles中+進(jìn)來,才會放到我們編譯后的文件中,包括三部分.a+.h+資源圖片,那么這個(gè)時(shí)候會出現(xiàn)一個(gè)問題:

將我們編譯好的.a+.h+資源文件作為一個(gè)靜態(tài)庫放入我們的主項(xiàng)目中,如果我們的主項(xiàng)目中已經(jīng)有一個(gè)同名圖片,然后對主項(xiàng)目進(jìn)行編譯后,發(fā)現(xiàn)包中只有一個(gè)同名的圖片.

為了解決這個(gè)問題,我們將圖片放到一個(gè)文件夾中,將這個(gè)文件夾放到和.a/.h同級目錄下,當(dāng)我們在主工程引用這個(gè)靜態(tài)庫的時(shí)候,需要將這個(gè)文件夾拖入主工程,但是我們用兩個(gè)選擇Create Group/Create folder references,由于我們將靜態(tài)庫導(dǎo)入到主工程,其實(shí)包括資源文件/.h/.a都已經(jīng)編譯好了,所以并不需要主工程對當(dāng)前的資源文件做出引用,應(yīng)該選擇Create folder references,這樣會將資源文件/.a/.h都加入到主工程的同級目錄下,否則會發(fā)現(xiàn)資源文件不見了.

但是如果選擇了Create Group,那么就會出問題,所以我們將資源文件放到bundle中進(jìn)行存放(),bundle中的資源并不會因?yàn)檫@兩個(gè)選項(xiàng)選錯(cuò)了就會把資源文件位置放錯(cuò),一直會放到同級目錄下.

(2).如果用戶導(dǎo)入的頭文件過多怎么辦?

我們自己先建立一個(gè)主頭文件,我們將所有的頭文件都導(dǎo)入到主頭文件中,我們直接import主頭文件就行

(3).靜態(tài)庫如何測試?

.a文件如果交給主工程測試無法定位問題所在

所以定義一個(gè)復(fù)合工程,進(jìn)行單元測試,在Targets中點(diǎn)擊+號,選擇Framework & Library 中的CocoaTouch Framework,新建一個(gè)Framework工程

添加Testframe復(fù)合工程

比如我們想要在A業(yè)務(wù)模塊中調(diào)試代碼,那么我們將A業(yè)務(wù)模塊代碼放到主工程中,調(diào)用我們想要編譯成靜態(tài)庫的代碼B,將B(以Tool類為例)

添加到Testframework中

在復(fù)合工程FrameworkTests中引入我們的靜態(tài)庫類,然后再主工程中調(diào)用Tool.h類進(jìn)行測試,如果沒問題,那么在Targets點(diǎn)中我們的復(fù)合工程Testframework,配置生成靜態(tài)庫的某些項(xiàng),編譯完之后,再Products中查找Testframework并查看包的內(nèi)容,生成合并的release靜態(tài)庫.

(4).當(dāng)我們將組建進(jìn)行二進(jìn)制化之后,那么導(dǎo)入方式將會改變,例如#import 'Tool.h'? #import <Framework/Tool.h>,如何避免多地方的改動?

我們可以將.h文件剝離出來,獨(dú)立于framework之外,引用的時(shí)候直接調(diào)用#import 'Tool.h',實(shí)現(xiàn)的時(shí)候還是在framework中進(jìn)行實(shí)現(xiàn)

(5).如何將生成的所有的架構(gòu)文件刪除某個(gè)架構(gòu),該如何操作?比如我們不需要支持i386

第一種:那么我們分別對其他的架構(gòu)生成靜態(tài)庫,然后將靜態(tài)庫合并

第二種:直接在生成的靜態(tài)庫中移除某一個(gè)架構(gòu), cd到當(dāng)前靜態(tài)庫的上一級,命令? ? ?

?lipo -remove i386 文件地址.a? -output? 生成的名字.a

如果只要某一個(gè)架構(gòu)的文件 比如arm64:

lipo -thin arm64 文件地址.a -output 生成名.a


接下來我們將framework放到遠(yuǎn)端倉庫

以之前創(chuàng)建的一個(gè)WKDownLoad私有庫為例首先創(chuàng)建一個(gè)Framework 項(xiàng)目WKDownloadLb,將WKDownLoad中的代碼放到WKDownloadLb中,并暫時(shí)刪除自帶的WKDownloadLb.h文件,Xcode配置相應(yīng)的生成framework的某些項(xiàng),mach-o-Type/Build Active Architecture Only/run->release

生成的framwork項(xiàng)目

接下來,為了能夠方便的查找我們生成framework位置,需要對xcode進(jìn)行配置File->Project Settings

Project Settings
具體存放位置

將framework存放到相對于workspace的同級目錄下的products文件下,開始進(jìn)行編譯,然后將framework進(jìn)行合并,合并完之后,我們可以將WKDownloadLb.framework放到Products中,把iphoneos/iphonesimulator刪掉

編譯后的路徑

接下來將原來的WKDownLoad中的podspec文件拷貝一份放到我們的WKDownloadLb項(xiàng)目中,用于進(jìn)行pod時(shí)的查找,并修改podspec,包括庫的名稱/homepage/source/,在初始化coding.net一個(gè)項(xiàng)目的時(shí)候,不要設(shè)置git.ignore,將coding.net中的homepage/source分別放到podspec對應(yīng)位置

為了外界不用改動引入我們.h文件的方式,我們做一層兼容,在framework外把所有的.h文件都加進(jìn)來(真實(shí)情況是將所有.h文件都加都一個(gè)文件中,只引用某一個(gè)文件就行),在根目錄下創(chuàng)建一個(gè)文件夾,把所有的.h文件都拷貝一份放到這里.

.h的header文件夾

修改source_files/s.vendored_frameworks,其中vendored_frameworks其實(shí)是指明我們framework的地址專門存在的,由于已經(jīng)將framework放到了products中,所以地址更短了;source_files是除了framework之外的而外信息,就是我們的暴露header

framework/header設(shè)置

修改完之后,按照

git add .

git status

git commit -m '標(biāo)記'

git remote

git remote add origin 地址

git push origin master

git tag -a 'tag值' -m '打標(biāo)簽'

git push --tags

pod lib lint? ?

(1)第一種錯(cuò)誤

pod lib lint 第一種錯(cuò)誤

發(fā)現(xiàn)好多小伙伴報(bào)這種錯(cuò)誤,

解決方案:

pod repo push 私有spec xxxxxx.podspec --allow-warnings --skip-import-validationpod spec lint xxxxxx.podspec --skip-import-validation

參考地址

這個(gè)問題困擾了我很久,終于解決了,感謝小伙伴的貢獻(xiàn)啊.

(2)第二種錯(cuò)誤

pod lib lint 第二種錯(cuò)誤

是由于tag沒提交遠(yuǎn)端或者podspec中tag不一致導(dǎo)致的.


最終方案

我們現(xiàn)在遠(yuǎn)程倉庫有一個(gè)原生代碼組件和一個(gè)靜態(tài)庫組件,那么我們這樣有一個(gè)弊端,需要改兩個(gè)組件庫才能將兩個(gè)庫中代碼修改完畢,并且需要進(jìn)行pod文件名稱的修改,很不方便

能不能合并到一個(gè)里邊那?答案是肯定滴

再原來pod lib create 創(chuàng)建的私有庫demo中創(chuàng)建一個(gè)framework的復(fù)合工程

復(fù)合工程

將framework復(fù)合工程中的部分中引入對原來類的引用,注意只是引用,并不拷貝,這樣就能保證修改的是一份代碼.

引用

生成的framework復(fù)合工程部分,引用完之后代碼結(jié)構(gòu)

代碼結(jié)構(gòu)

為了生成靜態(tài)庫,需要在復(fù)合項(xiàng)目的build Setting工程目錄下修改相應(yīng)的配置,release/mach-o/build avtive/修改暴露外界的.h到Public中等,然后編譯生成靜態(tài)framework庫,合并真機(jī)和模擬器的可執(zhí)行文件,放到原來組件的Classes的同級目錄下

products同級目錄下

?接下來,修改podspec文件,并設(shè)置靜態(tài)庫暴露在外的頭文件以及framework靜態(tài)庫

設(shè)置原來組件的podspec

修改暴露的source_files為暴露classes中的.h,添加引用的framework地址,這樣就算設(shè)置完畢了.

接下來我們將修改后的組件上傳到原來未二進(jìn)制化時(shí)的私有庫中

進(jìn)行上傳...

在其他地方調(diào)用本組件,會發(fā)現(xiàn)已經(jīng)二進(jìn)制化了??,搞定

最終將上傳到私有庫的framework進(jìn)行pod install,但是報(bào)了一個(gè)錯(cuò)誤

pod install

發(fā)現(xiàn)是由于在pod file中打開了use_frameworks!,注掉就行

我們可以發(fā)現(xiàn):這樣并不需要添加一個(gè)新的pod依賴,并且通過pod update --no-repo-update就可以更新我們的遠(yuǎn)端私有庫,又節(jié)省了遠(yuǎn)端私有庫的資源

最后兼容源碼和靜態(tài)庫兩種類型

pod 中是可以設(shè)置環(huán)境變量的,比如 xxx pod install,xxx就是我們的環(huán)境變量

安裝的時(shí)候 IS_SOURCE=1 pod install,就會把原生代碼加進(jìn)來了

兼容原生和二進(jìn)制

注意的地方:

1.如果我們生成的是.a的靜態(tài)庫,并不是framework靜態(tài)庫,那么需要將s.vendored_framework換成s.vendored_libraries就行了

2.如果原來是framework,再IS_SOURCE=1 pod install到原生,那么會發(fā)現(xiàn)安裝進(jìn)來的私有庫.m文件找不到了,這時(shí)需要先將之前的緩存清掉 pod cache clean --all,再將pods文件夾全部刪除,這個(gè)時(shí)候再執(zhí)行IS_SOURCE=1 pod install

3.如果我們的私有庫都用這個(gè)環(huán)境變量控制,就能起到統(tǒng)一管理私有庫源碼或者二進(jìn)制文件導(dǎo)入,但是這個(gè)時(shí)候有一個(gè)問題,如何只設(shè)置某一個(gè)為原生代碼?其他都為二進(jìn)制

可以給每一個(gè)私有庫單獨(dú)設(shè)置一個(gè)變量,表示當(dāng)前私有庫需要設(shè)置二進(jìn)制 - WKDownload

單獨(dú)設(shè)置為原生

執(zhí)行WKDownload=1 pod install ,這樣,私有庫中的所有代碼都設(shè)置為二進(jìn)制形式,除了WKDownload為原生

4.私有庫中有依賴,那么怎么處理

不應(yīng)該包含依賴的xxx.a/framework文件

并且比如包含很多subspec,那么我們需要將所有的都放到一個(gè)framework中

快速生成framework

最后,為了方便誉尖,我們很多時(shí)候可以利用cocoapods-packager來快速完成framework打包罪既,但是必須注意,我們需要將原來的源碼已經(jīng)用上傳到托管平臺铡恕,并且已加了tag野崇。

1.安裝package

安裝

2.根據(jù)生成靜態(tài)庫

靜態(tài)庫生成

3.查看支持的類型

支持的類型

4.把不需要的類型刪除

刪除

根據(jù)路徑下的庫中的podspec文件问慎,生成相對應(yīng)的framework奖蔓,并且支持所有的機(jī)型以蕴,個(gè)人比較傾向于這個(gè)工具。

包含subspec的靜態(tài)庫的封裝

如果有framework里有依賴祭刚,那么我們不能用自動化的cocoapods packager打包framework框架里.

組合項(xiàng)目里創(chuàng)建target framework來進(jìn)行靜態(tài)庫的封裝,打包完之后其實(shí)是不包含我們的第三方依賴的,

我們的復(fù)合項(xiàng)目中想要用第三方的框架中的代碼,那么需要將我們創(chuàng)建的target放入pod中,根據(jù)pod 文件的修改

pod 文件添加framework類

修改podspec? 去掉之前色subspec,將所有的代碼看成一個(gè)整體

修改podspec 文件里添加source_files/vendored_frameworks

去掉? 庫名稱.dependency? ? ? '依賴庫名稱'

然后按照framwork的封裝進(jìn)行提交到私有庫



歡迎關(guān)注我的公眾號,專注iOS開發(fā)涡驮、大前端開發(fā)暗甥、跨平臺技術(shù)分享。

iOS開發(fā)之家
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捉捅,一起剝皮案震驚了整個(gè)濱河市撤防,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棒口,老刑警劉巖寄月,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異无牵,居然都是意外死亡漾肮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門茎毁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來克懊,“玉大人,你說我怎么就攤上這事七蜘√犯龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵橡卤,是天一觀的道長扮念。 經(jīng)常有香客問我,道長碧库,這世上最難降的妖魔是什么扔亥? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮谈为,結(jié)果婚禮上旅挤,老公的妹妹穿的比我還像新娘。我一直安慰自己伞鲫,他們只是感情好粘茄,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秕脓,像睡著了一般柒瓣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吠架,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天芙贫,我揣著相機(jī)與錄音,去河邊找鬼傍药。 笑死磺平,一個(gè)胖子當(dāng)著我的面吹牛魂仍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拣挪,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼擦酌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了菠劝?” 一聲冷哼從身側(cè)響起赊舶,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赶诊,沒想到半個(gè)月后笼平,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舔痪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年寓调,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辙喂。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捶牢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巍耗,到底是詐尸還是另有隱情秋麸,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布炬太,位于F島的核電站灸蟆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亲族。R本人自食惡果不足惜炒考,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望霎迫。 院中可真熱鬧斋枢,春花似錦、人聲如沸知给。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涩赢。三九已至戈次,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筒扒,已是汗流浹背怯邪。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留花墩,地道東北人悬秉。 一個(gè)月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓澄步,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搂捧。 傳聞我的和親對象是個(gè)殘疾皇子驮俗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

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