iOS靜態(tài)庫(kù)SDK制作(包含第三方靜態(tài)庫(kù))

前言

以下所涉及的框架和庫(kù)只針對(duì)iOS而言,不確保在其他平臺(tái)也適用。

最近由于公司業(yè)務(wù)需要,要求封裝一個(gè)支付SDK,需要用到微信支付和支付寶,之前做過(guò)的Framework沒(méi)有依賴其他第三方的庫(kù)所以比較好做,這次有所不同;一開始我想把支付寶和微信支付的SDK全部融合進(jìn)來(lái),折騰一天才發(fā)現(xiàn)我之前的想法有很多誤區(qū),這樣是根本行不通的,不過(guò)最后還是封裝成功了,下面把我的經(jīng)驗(yàn)分享出來(lái),供有需要的同學(xué)少走彎路。 制作之前最好把功課做足,看看靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)到底是什么東西。

轉(zhuǎn)載請(qǐng)注明出處:來(lái)自LeonLei的博客http://www.gaoshilei.com

一. 靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的詳細(xì)介紹

我們平時(shí)的工程中或多或少都要引入第三方的SDK,就算你沒(méi)有引入第三方的,至少引用過(guò)系統(tǒng)的Framework吧?其實(shí)這些SDK和Framework都屬于庫(kù),庫(kù)又分為靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù),我們平時(shí)導(dǎo)入的第三方SDK有的是Framework,有的是.a,到底哪些是動(dòng)態(tài)庫(kù),哪些是靜態(tài)庫(kù)呢?下面分別介紹靜態(tài)庫(kù)、動(dòng)態(tài)庫(kù),F(xiàn)ramework和.a以及.dylib/.tbd區(qū)別

一. 靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)

首先要解釋一下什么是庫(kù),庫(kù)(Library)其實(shí)就是一段編譯好的二進(jìn)制代碼,加上頭文件就可以供別人使用,一般會(huì)有兩種情況要用到庫(kù):

  • 某些代碼需要給別人使用,但是我們不希望別人看到源碼,就需要以庫(kù)的形式進(jìn)行封裝,只暴露出頭文件。
  • 對(duì)于某些不會(huì)進(jìn)行大的改動(dòng)的代碼,比方說(shuō)很多大公司常用且很少變動(dòng)的模塊都會(huì)編譯成庫(kù),這樣做的好處一是可以節(jié)省編譯時(shí)間,二來(lái)對(duì)于代碼的管理也非常方便。

因?yàn)閹?kù)是已經(jīng)編譯好的二進(jìn)制文件了,編譯的時(shí)候只需要link一下,既然提到了link那就有不同的形式了,靜態(tài)和動(dòng)態(tài),與之相對(duì)應(yīng)的就是靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)。

1. 靜態(tài)庫(kù)

平時(shí)我們用的第三方SDK基本上都是靜態(tài)庫(kù),靜態(tài)庫(kù)的幾個(gè)特點(diǎn):

  • 在App項(xiàng)目編譯的時(shí)候會(huì)被拷貝一份編譯到目標(biāo)程序中,相當(dāng)于將靜態(tài)庫(kù)嵌入了,所以得到的App二進(jìn)制文件會(huì)變大。
  • 在使用的時(shí)候,需要手動(dòng)導(dǎo)入靜態(tài)庫(kù)所依賴的其他類庫(kù)。(比如說(shuō)某個(gè)SDK中使用到了CoreMotion.framework,在使用的時(shí)候需要手動(dòng)導(dǎo)入。有的SDK需要link十幾個(gè)系統(tǒng)庫(kù),這個(gè)時(shí)候非常惡心,只能一個(gè)一個(gè)手動(dòng)加,這是靜態(tài)庫(kù)一個(gè)很大的不便之處。)
  • 導(dǎo)入靜態(tài)庫(kù)的應(yīng)用可以減少對(duì)外界的依賴,如果導(dǎo)入的是第三方動(dòng)態(tài)庫(kù),動(dòng)態(tài)庫(kù)找不到的話應(yīng)用就會(huì)崩掉,例如Linux上經(jīng)常出現(xiàn)的lib not found。
  • 靜態(tài)庫(kù)很大的一個(gè)優(yōu)點(diǎn)是減少耦合性,因?yàn)殪o態(tài)庫(kù)中是不可以包含其他靜態(tài)庫(kù)的,使用的時(shí)候要另外導(dǎo)入它的依賴庫(kù),最大限度的保證了每一個(gè)靜態(tài)庫(kù)都是獨(dú)立的,不會(huì)重復(fù)引用。

2. 動(dòng)態(tài)庫(kù)

這個(gè)是我們最常用的一類庫(kù),使用頻率最高的UIKit.framework和Fundation.framework都屬于動(dòng)態(tài)庫(kù),所有.dylib和.tbd結(jié)尾的都屬于動(dòng)態(tài)庫(kù)。動(dòng)態(tài)庫(kù)的幾個(gè)特點(diǎn):

  • 平時(shí)使用的系統(tǒng)庫(kù)都放在iOS系統(tǒng)中,在你打包應(yīng)用程序的時(shí)候這些庫(kù)不會(huì)拷貝到你的程序中,當(dāng)需要使用的時(shí)候會(huì)動(dòng)態(tài)從iOS系統(tǒng)中加載它們,因?yàn)檫@個(gè)原因,動(dòng)態(tài)庫(kù)也被稱作共享庫(kù)。編譯時(shí)才載入的特性,也可以讓我們隨時(shí)對(duì)庫(kù)進(jìn)行替換,而不需要重新編譯代碼。
  • 這些庫(kù)是所有應(yīng)用公用的,換一種說(shuō)法就是節(jié)省了應(yīng)用安裝包的體積,這是區(qū)別靜態(tài)庫(kù)很重要的一個(gè)特點(diǎn),因?yàn)殪o態(tài)庫(kù)使用一次就要拷貝一次,非常浪費(fèi)資源。
  • 動(dòng)態(tài)庫(kù)在制作的時(shí)候可以直接包含靜態(tài)庫(kù),也能自動(dòng)link所需要的依賴庫(kù)。
  • 使用動(dòng)態(tài)庫(kù)的時(shí)候不需要再次link依賴庫(kù),即導(dǎo)即用,這個(gè)就厲害了。唯一需要注意的是在導(dǎo)入自己制作的動(dòng)態(tài)庫(kù)時(shí),需要在Embedded Binaries中導(dǎo)入,不然會(huì)報(bào)錯(cuò):image not found。此時(shí)這個(gè)動(dòng)態(tài)庫(kù)會(huì)跟靜態(tài)庫(kù)一樣被拷貝到目標(biāo)程序中進(jìn)行編譯,蘋果又把這種Framework叫做Embedded Framework

關(guān)于動(dòng)態(tài)庫(kù)要搞清楚一點(diǎn),我們自己制作的動(dòng)態(tài)庫(kù)與系統(tǒng)動(dòng)態(tài)庫(kù)的區(qū)別,我們自己制作的動(dòng)態(tài)庫(kù)引入App項(xiàng)目的時(shí)候需要embed進(jìn)項(xiàng)目,也就是要拷貝到目標(biāo)程序中,這就有點(diǎn)不像動(dòng)態(tài)庫(kù)的特性了,蘋果這么做也是考慮安全問(wèn)題吧!
至于能不能正常上架,我也不清楚,查了大量資料都是抄來(lái)抄去沒(méi)說(shuō)清楚,我猜測(cè)是不能上架的,因?yàn)橐话愕牡谌絊DK也都是靜態(tài)庫(kù)的形式,我猜測(cè)一個(gè)重要原因是iOS的應(yīng)用本來(lái)就是運(yùn)行在沙盒里面的,不同應(yīng)用之間不能共享代碼,同時(shí)動(dòng)態(tài)下載代碼蘋果肯定也是明令禁止的,所以動(dòng)態(tài)庫(kù)也就失去意義了。當(dāng)然可能還有其他因素,歡迎交流學(xué)習(xí)!

二. Framework、.a、.dylib/.tbd

1. Framework

Framework的英文釋意是框架,主要由Headers、binary文件、.bundle這三部分構(gòu)成,除此之外還有Info.plist和Modules,后兩者主要記錄Framework的版本之類的信息,一般都會(huì)刪掉,不做討論

  • Headers
    包含我們?cè)谥谱鱂ramework的時(shí)候暴露的頭文件,所有被暴露的.h都放在這里。
  • binary文件
    整個(gè)Framework的核心,所有代碼都被編譯成了這樣一坨二進(jìn)制文件,這里要注意的是添加的依賴庫(kù)不會(huì)被編譯進(jìn)來(lái),用的時(shí)候還需要重新link其他依賴庫(kù)。
  • .bundle
    資源文件都打包放在這里。在制作Framework的時(shí)候不可以把圖片直接放在項(xiàng)目中,否則制作好之后圖片是一張一張的出現(xiàn)在項(xiàng)目中非常亂,需要新建一個(gè)bundle將圖片放進(jìn)去,這里的bundle提供整個(gè)SDK的圖片資源。
    注意:圖片放進(jìn)bundle之后不可以用[UIImage ImageWithName:]讀取圖片。要先找到bundle包再拿圖片。

這里要糾正一個(gè)誤區(qū)

很多人認(rèn)為系統(tǒng)的Framework就是動(dòng)態(tài)庫(kù),我們自己制作的Framework就是靜態(tài)庫(kù)。

其實(shí)Framework既可以是靜態(tài)庫(kù)也可以是動(dòng)態(tài)庫(kù),這取決于編譯成的Mach-O(就是那個(gè)二進(jìn)制文件)是動(dòng)態(tài)庫(kù)還是靜態(tài)庫(kù),F(xiàn)ramework本質(zhì)上并不是一個(gè)庫(kù),它是蘋果為了方便開發(fā)者提供了一種庫(kù)的打包方式,F(xiàn)ramework會(huì)將Mach-O文件、頭文件和資源包全都包含進(jìn)來(lái),不需要你再手動(dòng)整理,我們也可以通過(guò)Xcode來(lái)制作framework動(dòng)態(tài)庫(kù)使用。
所以總結(jié): Framework是庫(kù)的打包形式,既可以是動(dòng)態(tài)庫(kù)也是靜態(tài)庫(kù)。

2. .a靜態(tài)庫(kù)

這類靜態(tài)庫(kù)與Framework基本類似,不同的是在打包成.a文件的同時(shí),還需要提供頭文件,使用時(shí)相較于Framework比較麻煩,(例如微信支付SDK使用的是.a,不同的是支付寶SDK是以framework的形式打包的)。.a這樣打包不夠方便,而Framework編譯完成暴露的頭文件都已經(jīng)放好了。

3. .dylib/.tbd 動(dòng)態(tài)庫(kù)

這類動(dòng)態(tài)庫(kù)我們也經(jīng)常用,基本上都是系統(tǒng)提供的,一般不能自己制作,就算你通過(guò)其他方式制作使用,也肯定不能上架的,這里沒(méi)什么好講的。

二. Framework(靜態(tài)庫(kù)+動(dòng)態(tài)庫(kù))的制作

動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)的制作流程基本一樣,包括頭文件的暴露等,唯一不同的是Mach-O文件的編譯形式。本節(jié)將介紹Xcode制作Framework的過(guò)程,本次制作的Framework靜態(tài)庫(kù)依賴其他第三方靜態(tài)庫(kù)(Framework和.a)。

1> 新建工程

新建Framework工程

這里要選Framework,如果選擇右邊的Static Library制作出來(lái)的是.a靜態(tài)庫(kù)。

2> 導(dǎo)入所有要打包的文件和其他第三方靜態(tài)庫(kù)
正常導(dǎo)入要打包的文件就可以了,在導(dǎo)入第三方靜態(tài)庫(kù)的時(shí)候要注意,不要選擇添加到target中,如果添加進(jìn)去要去target里面把第三方靜態(tài)庫(kù)刪掉(只需導(dǎo)入,不要添加進(jìn)target)

導(dǎo)入第三方靜態(tài)庫(kù)

導(dǎo)入第三方靜態(tài)庫(kù)之后再link依賴的系統(tǒng)庫(kù),像這樣
link依賴庫(kù)

注意上面的運(yùn)行目標(biāo),因?yàn)槲矣玫氖荴code8,最低支持到iOS8。
要打包的文件和第三方靜態(tài)庫(kù)全部導(dǎo)入完成
所有文件導(dǎo)入情況

3> 項(xiàng)目性質(zhì)修改
把項(xiàng)目的membership需改為public,否則頭文件暴露將會(huì)不正常

修改項(xiàng)目的membership

4> 暴露頭文件
將頭文件暴露出去,供外界使用,所有的編譯文件都在Project中,需要右擊添加到public里面

暴露頭文件

5> 選擇Mach-O的編譯方式
這是最重要的一步,這一步?jīng)Q定我們制作出來(lái)的是靜態(tài)庫(kù)還是動(dòng)態(tài)庫(kù),默認(rèn)選擇的是Dynamic Library,要手動(dòng)選擇Static Library

Mach-O 形式

6> 編譯
如果你的依賴庫(kù)里面有l(wèi)ib開頭的dylib動(dòng)態(tài)庫(kù),此時(shí)應(yīng)該會(huì)報(bào)錯(cuò)

動(dòng)態(tài)庫(kù)鏈接報(bào)錯(cuò)

什么意思呢?大概就是沒(méi)找到對(duì)應(yīng)的庫(kù)文件,因?yàn)閠bd是蘋果提供的新的動(dòng)態(tài)庫(kù)格式,之前都是dylib,不知道這里又抽什么風(fēng),下面解決問(wèn)題。

7> tbd動(dòng)態(tài)庫(kù)報(bào)錯(cuò)修改
先把原來(lái)的.tbd刪掉,然后再次添加,這個(gè)時(shí)候選擇add other,在彈出的窗口中按快捷鍵shift + command + G 調(diào)出finder的前往窗口,輸入/usr/lib,然后添加相應(yīng)的dylib動(dòng)態(tài)庫(kù)

修改的動(dòng)態(tài)庫(kù)

替換完成之后重新編譯項(xiàng)目,生成Framework(可在Product文件中右擊在finder中顯示找到)

8> 使用
新建一個(gè)文件夾,將制作好的靜態(tài)庫(kù)拷貝出來(lái)放進(jìn)去,再將第三方靜態(tài)庫(kù)拷貝到相同的文件夾中,此時(shí)只要將這個(gè)文件夾提供給外界使用就可以了,這是我寫的測(cè)試demo驗(yàn)證打包好的SDK是否可以正常使用

制作完成使用

至此我們已經(jīng)完成了Framework中包含其他第三方靜態(tài)庫(kù)的制作。
如果需要制作動(dòng)態(tài)庫(kù),只需要在第5步中將Mach-O的形式改為Dynamic Library就可以了,其他步驟一樣

如果有問(wèn)題請(qǐng)?jiān)诹粞詤^(qū)留言,或者郵件給我,互相交流學(xué)習(xí)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容