前言:今天公司項(xiàng)目準(zhǔn)備使用高德導(dǎo)航,其中用到了高德3D地圖SDK,然后就出現(xiàn)bug了。在真機(jī)上可以完美運(yùn)行,但是在模擬器上,就出現(xiàn)了一大片的bug:提示有82個(gè)Duplicate symbols,仔細(xì)一看是MobileVLCKit和高德的MAMapKit之間的問題。(PS:今天是真心累啊,不過解決了bug,還是很值得的。)
現(xiàn)在,我就今天踩過的坑,做個(gè)簡(jiǎn)單的整理,以備以后翻看。 也希望以后遇到類似坑的小伙伴們,可以有些許啟發(fā)和不同見解。
問題描述及猜想
上圖為部分報(bào)錯(cuò)內(nèi)容。兩個(gè)第三方SDK之間在某些特定平臺(tái)存在一些duplicate symbols。分析:那是不是除掉其中一個(gè)SDK中相應(yīng)平臺(tái)上,重復(fù)的那部分symbols,是不是就解決問題了呢?且繼續(xù)向下看。
解決問題
通過查找資料,各種扒論壇,終于發(fā)現(xiàn),跟我一起踩坑的小伙伴們還真不少。
然后通過借鑒他們的經(jīng)驗(yàn),在對(duì)linux的相關(guān)語法實(shí)在小白的情況下,終于解決問題了,好感動(dòng)啊!!!
工具介紹
lipo
lipo是管理Fat File的工具, 可以查看平臺(tái)列表, 提取特定平臺(tái), 重新打包。
nm
nm用來顯示一個(gè)程序包的符號(hào)表, 默認(rèn)會(huì)顯示入口地址, 符號(hào)類型, 符號(hào)名。
strip
strip用來刪除程序里的符號(hào)表。-R 用來指定一個(gè)要?jiǎng)h除的符號(hào)列表, 使用上述生成的symbols文件.。添加 -S 選項(xiàng)來保留其他符號(hào)。
ar
ar可以查看一個(gè)程序包里的對(duì)象文件列表, 解壓出其中的對(duì)象文件并重新打包。
ld
ld蘋果系統(tǒng)下的鏈接器, 可以更精確的控制符號(hào)表的導(dǎo)出。
具體步驟
因?yàn)閾?dān)心修改MobileVLCKit對(duì)已上線的視頻播放造成不可估計(jì)的影響,因此,此次修改MAMapKit,出現(xiàn)任何bug也可以盡快發(fā)現(xiàn)并解決。
下面將進(jìn)行十分小白式的記錄(PS:主要是我太小白了。)
cd path(framework的路徑)
lipo -info MAMapKit
查看MAMapKit的適用平臺(tái),可以發(fā)現(xiàn)arm7,i386,x86_64,arm64均可用。并且前面bug只是存在于x86_64平臺(tái)上,那么就先修改這個(gè)平臺(tái)的內(nèi)容。
lipo -thin x86_64 MAMapKit -output MAMapKit.x86_64
文件瘦身,提取x86_64平臺(tái)的MAMapKit到新的文件MAMapKit.x86_64,發(fā)現(xiàn)該文件只有3M而已(源文件20.2M),該文件位置與MAMapKit相同,發(fā)現(xiàn)確實(shí)單個(gè)平臺(tái)的文件比較小。
nm -j MAMapKit.x86_64 | grep png > symbols
獲取MAMapKit.x86_64文件中以_png為前綴的所有符號(hào),生成符號(hào)列表并存于symbols文件中。( -j 選項(xiàng)控制只輸出符號(hào)名)
因?yàn)樯厦娴膕ymbols內(nèi)容不是上述bug中包含的內(nèi)容,因此,需要更改該symbols文件,刪除里面所有符號(hào),將報(bào)錯(cuò)的所有重復(fù)符號(hào)
_png_do_invert
_png_set_shift
_png_get_user_transfom_ptr
...
這些符號(hào)依次輸入到該文件中,每行一個(gè)。這就將本次需要?jiǎng)h除的符號(hào)存在符號(hào)列表中了。
ar -t MAMapKit.x86_64
可以發(fā)現(xiàn)整個(gè)包中就一個(gè)主要文件MAMapKit-x86_64-master.o文件,這也是前面bug中提到的重名符號(hào)所在的位置。(PS:更確定找對(duì)了方法)
ar -x MAMapKit.x86_64
可以發(fā)現(xiàn)多出了三個(gè)文件,也獲得了需要的MAMapKit-86_64-master.o文件。
ld -x -r -unexported_symbols_list symbols MAMapKit-x86_64-master.o -o MAMapKit-x86_64-master.o.strip
可以將symbols文件中的符號(hào)列表在MAMapKit-x86_64-master.o文件中刪除掉,并生成一個(gè)新的文件MAMapKit-x86_64-master.o.strip。
ar -r MAMapKit.x86_64 MAMapKit-x86_64-master.o.strip Pods-MAMapKit-dummy.o
- 在執(zhí)行此命令之前,可以將前面獲得MAMapKit.x86_64文件放在其他位置作為對(duì)比。
- 然后通過該命令得到一個(gè)新打包好的x86_64平臺(tái)包。
- 也可以用以前的獲取symbols的方式從這個(gè)新包中獲取相應(yīng)的_png的所有符號(hào)表,查詢剛才需要?jiǎng)h除的符號(hào),驗(yàn)證那些符號(hào)是否已被刪除。(很高興確實(shí)已經(jīng)刪除了,這下問題應(yīng)該可以解決了吧。)
下面將替換原有包中的x86_64平臺(tái)包。(該文件中只修改了x86_64平臺(tái)的內(nèi)容)
lipo MAMapKit -replace x86_64 MAMapKit.x86_64 -output MAMapKitTest
用上面生成的新包替換MAMapKit包中的x86_64平臺(tái)包,然后生成一個(gè)新的文件包,最后將舊的MAMapKit包移除,其他多余內(nèi)容也一并移除,將MAMapKitTest更名為MAMapKit。至此,MAMapKit.framework看起來跟原來的沒有什么區(qū)別了。(看事情不能只看表面哦,咱修改的是內(nèi)在!)
多余的話:如果修改多個(gè)平臺(tái)的包(因?yàn)槲抑恍枰薷膞86_64這一個(gè)平臺(tái)包),可能需要重新生成一個(gè)新包更合適。
- 根據(jù)前面的方法,生成每個(gè)平臺(tái)的新包;
- 將所有新包對(duì)應(yīng)各個(gè)平臺(tái),生成一個(gè)新包。
上圖紅色標(biāo)記即最后的合成新包方法。在此之前記得將前面更改過的x86_64平臺(tái)包拷貝到這些包的相同路徑下。
最后重新編譯工程,就這么完美解決了!!!這一刻的感覺,太激動(dòng)了。暫時(shí)未發(fā)現(xiàn)有什么問題,以后有什么由此衍生的bug,到時(shí)候再更新了。也希望小伙伴們共同學(xué)習(xí),有問題大家一定要指出來喲!歡迎大家找我交流問題一起進(jìn)步哦。
感謝下面兩位大神踩過的坑,有了它們的經(jīng)驗(yàn),才讓我如此順利的解決問題!
[1]Mac系統(tǒng)下lipo, ar, nm等工具的使用簡(jiǎn)介
[2]Lipo - 如何為ARMv7/ARMv7s/ARM64架構(gòu) 創(chuàng)建通用文件(Universal Files)](http://blog.csdn.net/volvet/article/details/50097563)