使用OC runtime解決第三方庫(kù)沖突且依賴庫(kù)版本不同

摘要OC runtime真是一個(gè)強(qiáng)大的東西,這次解決了第三方庫(kù)的沖突問(wèn)題

前幾天在iOS app項(xiàng)目中添加了幾個(gè)第三方庫(kù),各有各的用處,因?yàn)橐恍┰颍行?kù)是不開(kāi)源的。
添加后,發(fā)現(xiàn)app編譯不通過(guò),錯(cuò)誤如下:

從錯(cuò)誤描述中都能看出,app在連接過(guò)程中,發(fā)現(xiàn)了一些重復(fù)的符號(hào),即同樣的OC類和方法在不同的庫(kù)中都有實(shí)現(xiàn):liblibPDRCore.a和libsimpleconfiglib.a這兩個(gè)庫(kù)有沖突!恰好,這兩個(gè)庫(kù)都要用,而且都不開(kāi)源,仿佛一下子就走進(jìn)了死胡同,因?yàn)闆](méi)有辦法修改這兩個(gè)庫(kù)。
網(wǎng)上搜了一下,碰到這種問(wèn)題的人還真不少,也提出了解決方案:用lipo命令分解其中一個(gè)類,刪除重復(fù)的符號(hào),再用ar命令重新打包成庫(kù),我選擇修改liblibPDRCore.a這個(gè)庫(kù):
1.查看包信息:lipo -info liblibPDRCore.a,提示fat file,那么代表這個(gè)包是支持多平臺(tái)的,例如armv7,armv64等
2.取出armv7包:lipo liblibPDRCore.a -thin armv7 -output armv7/liblibPDRCore_armv7.a
3.解壓出object file(.o文件):cd armv7&ar xv liblibPDRCore_armv7.a
4.根據(jù)出錯(cuò)信息刪除PDRSerAsyncSocket.o:rm PDRSerAsyncSocket.o
5.重新打包:ar rcs liblibPDRCore_armv7.a *.o,記得把舊的庫(kù)刪掉
6.重復(fù)1-5把a(bǔ)rm64什么的一起改了
7.合并為fat庫(kù):lipo -create liblibPDRCore_armv7.a liblibPDRCore_arm64.a -output liblibPDRCore.a
好了,現(xiàn)在用新和成的庫(kù)替換,并編譯,發(fā)現(xiàn)編譯成功了!
且慢!這和主題OC runtime有什么關(guān)系?只是用一些工具去掉了重復(fù)符號(hào)!
是的,確實(shí)沒(méi)有關(guān)系,下面才正式進(jìn)入主題!
編譯是成功了,但實(shí)際運(yùn)行起來(lái)呢?非常抱歉,crash了,錯(cuò)誤如下:



原因可能是:這兩個(gè)庫(kù)雖然有一個(gè)名字一樣的OC類,有些方法也一樣,但并不是完全一樣,可以認(rèn)為,這兩個(gè)庫(kù)依賴了另一個(gè)開(kāi)源庫(kù),但不是同一個(gè)版本,仿佛又走進(jìn)死胡同鳥(niǎo)!
仔細(xì)分析了一些出錯(cuò)信息:liblibPDRCore.a某個(gè)地方調(diào)用了AsyncSocket類的方法acceptOnAddress:port:error:,但libsimpleconfiglib.a中的AsyncSocket卻沒(méi)有這個(gè)方法,造成調(diào)用異常。
現(xiàn)在輪到OC runtime上場(chǎng)了,我也只是抱著試一試的態(tài)度。前段時(shí)間正好看這方面內(nèi)容,了解到OC可以在運(yùn)行時(shí)動(dòng)態(tài)增加、替換一些類的方法,解決一些實(shí)際問(wèn)題。現(xiàn)在我想到一個(gè)思路:用一個(gè)空函數(shù),替代AsyncSocket類的方法acceptOnAddress:port:error:,看是否正常運(yùn)行
1.先獲取類類型:Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
2.給AsyncSocket類添加方法:class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"), IMP, types);,這個(gè)函數(shù)中,后面兩個(gè)參數(shù),一個(gè)是替換方法,一個(gè)是方法參數(shù)類型,替換方法參數(shù)好搞,直接定義一個(gè)C格式的函數(shù),傳函數(shù)指針即可;方法參數(shù)類型怎么弄?
于是,我想到了從libsimpleconfiglib.a庫(kù)中找一些蛛絲馬跡,雖然它和liblibPDRCore.a使用了不同版本的AsyncSocket類,但某些方法應(yīng)該是類似的,獲取可以幫我完成函數(shù)class_addMethod所需的最后一個(gè)參數(shù)
3.用lipo和ar命令獲得libsimpleconfiglib.a中的object file:"AsyncSocket.o"
4.查看"AsyncSocket.o"的導(dǎo)出符號(hào):nm AsyncSocket.o,果不其然,發(fā)現(xiàn)一個(gè)類似的,方法名不同,參數(shù)名卻一樣



5.再看一下liblibPDRCore.a庫(kù)中的PDRSerAsyncSocket.o的導(dǎo)出符號(hào),確實(shí)有"acceptOnAddress:port:error:"這個(gè)方法,我們知道,這個(gè)目標(biāo)文件已經(jīng)被我們?nèi)サ袅?br>

6.從名稱上判斷,這兩個(gè)方法參數(shù)一樣,而且方法acceptOnInterface確實(shí)存在,用method_getTypeEncoding來(lái)獲取方法的類型即可得到class_addMethod的最后一個(gè)參數(shù),用有了這個(gè)思路,完成了如下代碼:
<pre><code>

void impfunc(Class cls, SEL _cmd){

if([NSStringFromSelector(_cmd) isEqualtoString:@"acceptOnAddress"]) {

//調(diào)用cls的acceptOnInterace的方法 }}- (BOOL)application:...{

Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");

Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnInterface:port:error:"));

class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"),

(IMP)impfunc, method_getTypeEncoding(_acceptOnInterface));

}
</pre></code>

7.編譯并運(yùn)行起來(lái)之后,確實(shí)走到了impfunc,程序也不崩潰了,但相關(guān)的功能不正常,我想還是要真正調(diào)用一下acceptOnInterface這個(gè)方法才行

8.我想到了解析_cmd的參數(shù),取出參數(shù)值,然后再調(diào)用objc_msgSend發(fā)送消息,嘗試了很多方法,沒(méi)有成功;實(shí)際上,我還是走了彎路,各位應(yīng)該也看出來(lái)了,class_addMethod的第三個(gè)參數(shù),直接用acceptOnInterface的實(shí)現(xiàn)不就行了!method_getImplementation可以幫我們做到,于是代碼變成如下,編譯后運(yùn)行,成功了!

- (BOOL)application:...{    

Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");  

  Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass,
NSSelectorFromString(@"acceptOnInterface:port:error:"));   

 class_addMethod(_asyncSocketClass,

 NSSelectorFromString(@"acceptOnAddress:port:error:"), 
        
method_getImplementation(_acceptOnInterface ),    

 method_getTypeEncoding(_acceptOnInterface));

}
9.沒(méi)有了,散會(huì)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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