最近這段時(shí)間滥朱,一直在研究webrtc,寫iOS的時(shí)間很少力试,但是項(xiàng)目催得急徙邻,所以今天做了點(diǎn)iOS的工作。集成SDK本應(yīng)該是很簡(jiǎn)單的一件事情畸裳,但當(dāng)集成到一個(gè)維護(hù)長(zhǎng)達(dá)五年的項(xiàng)目中缰犁,問(wèn)題就多得一批。這里就順便把常見的坑總結(jié)下。
小坑
筆者這里的小坑大都是指不需要我們改很多東西的情況帅容,比如價(jià)格flag颇象,或者設(shè)置一下search path之類的。
NSAppTransportSecurity
如果需要集成的SDK做得并不是那么好并徘,很有可能在請(qǐng)求http的時(shí)候不成功遣钳。這個(gè)時(shí)候需要在plists文件設(shè)置一下,暫時(shí)退回到http協(xié)議麦乞。
- 在項(xiàng)目的info.plist中添加一個(gè)Key:NSAppTransportSecurity蕴茴,類型為字典類型。
- 然后給它添加一個(gè)Key:NSAllowsArbitraryLoads姐直,類型為Boolean類型倦淀,值為YES
pod 本地倉(cāng)庫(kù)太舊了或者pod search 搜索不到相關(guān)庫(kù)
比如在執(zhí)行pod install的時(shí)候出現(xiàn)找不到,比如什么頭文件找不到之類的声畏。解決辦法就是升級(jí)下pod庫(kù)
unrecognized selector sent to instance
很多時(shí)候這個(gè)問(wèn)題是因?yàn)榉诸惖膯?wèn)題撞叽。解決辦法:
工程--->Building Setting ——》Linking———>other linker flags 添加 -ObjC 或者-all_load
文件件.h找不到
直接在Building Setting里面設(shè)置搜索路徑。比如在有同學(xué)在集成支付寶的時(shí)候就經(jīng)常遇到:
解決辦法:
大坑
這里的大坑就是并不那么簡(jiǎn)單的就可以解決的插龄,至少需要你去了解下一些基本原理才能搞定的能扒。
Undefined symbols for architecture xxx
這個(gè)問(wèn)題大部分情況下還是比較好解決的,解決思路大致分為如下幾個(gè):
- 大部分情況下是忘記添加了某個(gè)系統(tǒng)framework或dylib辫狼,比如你在項(xiàng)目中使用了sqlite3初斑,但是沒(méi)有添加libsqlite3.dylib,就會(huì)出現(xiàn)這個(gè)問(wèn)題膨处。解決辦法是增加對(duì)應(yīng)的framework或dylib见秤。
- 如果是在C++里調(diào)用C函數(shù),檢查是否有添加extern "C"真椿,這可以通過(guò)觀察錯(cuò)誤提示中的函數(shù)名形式來(lái)決定鹃答,如果是C函數(shù)而以C ++的方式調(diào)用就需要添加extern "C"。
- 如果是把其它工程的xcodeproj文件加入到當(dāng)前項(xiàng)目中突硝,檢查Build Phases中的Target Dependencies有沒(méi)有添加依賴测摔,以及General中的Linked Frameworks and Libraries有沒(méi)有添加相關(guān)的.a文件。
- 如果添加.a文件編譯無(wú)錯(cuò)而添加xcodeproj文件編譯出錯(cuò)可參考3
- 如果添加.a文件編譯出錯(cuò)解恰,首先檢查其對(duì)應(yīng)的頭文件是否添加正確锋八,或者在Build Setting中有沒(méi)有添加對(duì)應(yīng)的Header Search Path路徑;其次檢查.a文件的c++編譯選項(xiàng)與當(dāng)前項(xiàng)目的c++編譯選項(xiàng)是否一致护盈;最后檢查.a文件與當(dāng)前項(xiàng)目的CPU架構(gòu)信息是否一致
- 如果是使用了靜態(tài)庫(kù)挟纱,真機(jī)Debug測(cè)試時(shí)正常,而在執(zhí)行for iOS Device測(cè)試時(shí)報(bào)這個(gè)錯(cuò)誤腐宋,很可能是因?yàn)殪o態(tài)庫(kù)支持的架構(gòu)不全紊服。出現(xiàn)這種情況是Build Setting中的Build Active Architecture Only在Debug下設(shè)為Yes檀轨,從而使得真機(jī)Debug測(cè)試正常。
符號(hào)文件沖突??
特征就是出現(xiàn)duplicate symbol這種標(biāo)志欺嗤。解決方法由易到難有如下幾個(gè):
- 對(duì)項(xiàng)目buildsetting里的other linker flags進(jìn)行修改参萄。詳細(xì)的方法可以看看這里iOS 解決一個(gè)因三方靜態(tài)庫(kù)沖突產(chǎn)生的duplicate symbol的問(wèn)題
- 這個(gè)方法就是從.a中把沖突的.o刪去。詳細(xì)步驟如下煎饼。
- 查看庫(kù)所包含的CPU架構(gòu)
打開終端輸入如下命令:
cd /Users/fww/Desktop/temp
lipo -info temp.a
輸出結(jié)果:
Architectures in the fat file: temp.a are: i386 x86_64 armv7 arm64
- 分離不同架構(gòu)的靜態(tài)庫(kù)
也就是說(shuō)這里將會(huì)從xxx.a中分離出i386 拧揽、x86_64、 armv7 腺占、arm64 四個(gè)架構(gòu)下的靜態(tài)庫(kù)淤袜,分別取名temp_i386.a,temp_x86_64.a,temp_armv7.a,temp_arm64.a: 在終端中繼續(xù)輸入如下命令:
lipo -extract_family i386 -output temp_i386.a temp.a lipo -extract_family x86_64 -output temp_x86_64.a temp.a lipo -extract_family armv7 -output temp_armv7.a temp.a lipo -extract_family arm64 -output temp_arm64.a temp.a
驗(yàn)證:
lipo -info temp_i386.a input file temp_i386.a is not a fat file Non-fat file: temp_i386.a is architecture: i386
lipo -info temp_x86_64.a input file temp_x86_64.a is not a fat file Non-fat file:temp_x86_64.a is architecture: x86_64
lipo -info temp_armv7.a input file temp_armv7.a is not a fat file Non-fat file: temp_armv7.a is architecture: armv7
- 刪除沖突的xxx.o
ar -d temp_i386.a GDataXMLNode.o ar -d temp_x86_64.a GDataXMLNode.o ar -d temp_armv7.a GDataXMLNode.o ar -d temp_arm64.a GDataXMLNode.o
- 合并為新的庫(kù)
刪除沖突的庫(kù)之后,將不同架構(gòu)下的靜態(tài)庫(kù)再重新合并起來(lái),取名:temp_new.a
lipo -create -output temp_new.a temp_i386.a temp_x86_64.a temp_armv7.a temp_arm64.a
底層庫(kù)比如openssl之類的沖突
如果遇到這種問(wèn)題就不能用上面講的刪除沖突的.o文件了衰伯。筆者親自用如下方法解決了前公司一個(gè)非常大的問(wèn)題铡羡。也就是在集成網(wǎng)易云信的時(shí)候,grpc中的boringssl和云信sdk中用到的openssl沖突了意鲸。剛開始網(wǎng)易云信的哥們直接說(shuō)搞不定烦周,后來(lái)在筆者親自試驗(yàn)下,給網(wǎng)易云信的哥們說(shuō)了方法怎顾,結(jié)果成功了读慎。后來(lái)他們把這個(gè)步驟寫在了官方網(wǎng)站上。
鏈接[ 解決 openSSL 和 boringSSL 沖突的問(wèn)題
當(dāng)時(shí)的思路出發(fā)點(diǎn)是來(lái)自于動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)加載機(jī)制的不同槐雾,靜態(tài)庫(kù)是一開始就加載了夭委,而動(dòng)態(tài)庫(kù)是在運(yùn)行的時(shí)候才加載。從而錯(cuò)開了兩者符號(hào)加載的時(shí)機(jī)募强。
打包動(dòng)態(tài)庫(kù)腳本如下:
#change your project name here
project_name="targetName"
#archs,include iphone (armv7, arm64) and iphone simulator (i386, x86_64)
archs="armv7 armv7s arm64"
for arch in $archs
do
echo "building $arch..."
if [ "$arch" = "i386" -o "$arch" = "x86_64" ]
then
xcrun_sdk="iphonesimulator"
export cflags_config="-fembed-bitcode-marker"
else
xcrun_sdk="iphoneos"
export cflags_config="-fembed-bitcode -Qunused-arguments"
fi
xcodebuild clean build ARCHS=$arch -sdk $xcrun_sdk TARGET_BUILD_DIR="./build-$arch" BUILT_PRODUCTS_DIR="./build-$arch" OTHER_CFLAGS="$OTHER_CFLAGS $cflags_config"
done
cp -rf ./build-arm64/$project_name.framework $project_name.framework
echo "generate product..."
lipo -create `find ./build-* -name $project_name` -output $project_name.framework/$project_name
echo "clean cache..."
#rm -rf ./build ./build-*
echo "done!"
一個(gè)庫(kù)必須使用動(dòng)態(tài)庫(kù)use_frameworks!株灸,另一個(gè)不能使用動(dòng)態(tài)庫(kù)
今天遇到了這個(gè)蛋疼的問(wèn)題。著名的加密庫(kù)libsodium和集成的另一個(gè)sdk出現(xiàn)了這種問(wèn)題擎值。而且這個(gè)sdk依賴了一大堆其他庫(kù)慌烧,比如AF,SD鸠儿。
由于這個(gè)SDK必須是動(dòng)態(tài)庫(kù)屹蚊,那么最終他依賴的第三方庫(kù)也必須用動(dòng)態(tài)庫(kù)的方式引入。這點(diǎn)自己弄了好了才得出這個(gè)結(jié)論进每。
并且有項(xiàng)目之前用過(guò)老版本的AF汹粤,并且還改了一大堆代碼,這個(gè)庫(kù)又用的新版AF品追。真實(shí)蛋疼玄括。
解決辦法:
- 解決掉老版本AF和新版AF:通過(guò)重命名老版本AF所有文件冯丙,這樣就徹底把老版本和新版本區(qū)分開肉瓦。得出的經(jīng)驗(yàn)是遭京,如果你決定改第三方庫(kù)源碼,那就馬上全部重命名泞莉,因?yàn)閷?duì)你而言這個(gè)庫(kù)已經(jīng)不是第三方庫(kù)了哪雕。。重命名的過(guò)程當(dāng)然是痛苦的鲫趁,因?yàn)橛玫降牡胤教嗨购浚@就是前人挖坑后人踩坑。
- 將libsodium打包成動(dòng)態(tài)庫(kù):因?yàn)閘ibsodium使用c語(yǔ)言寫的挨厚,這里讀者需要懂點(diǎn)linux/unix下的交叉編譯知識(shí)堡僻。用automake來(lái)實(shí)現(xiàn)跨平臺(tái)編譯。幸好這個(gè)庫(kù)已經(jīng)把相關(guān)的config文件以及生成iOS平臺(tái)的shell腳本寫好了疫剃。****但這中間有一個(gè)嚴(yán)重的坑钉疫,坑,坑巢价!
- 那就是不要去github項(xiàng)目主頁(yè)上下載源碼牲阁。因?yàn)橄孪聛?lái)沒(méi)有config文件。
- 應(yīng)該去下打包好的項(xiàng)目壤躲。也就是xx.tag.xxx這種格式的城菊。
- 然后下載下來(lái),把iOS.sh從dist_build目錄放到項(xiàng)目根目錄下碉克。
- 然后執(zhí)行
sh iOS.sh
凌唬。過(guò)一段時(shí)間,.a庫(kù)就生成好了漏麦。
- 生成的.a庫(kù)打包成動(dòng)態(tài)庫(kù)法瑟,大致步驟就是建一個(gè)動(dòng)態(tài)庫(kù)工程,把生成的靜態(tài)庫(kù)項(xiàng)目拖到動(dòng)態(tài)庫(kù)項(xiàng)目中唁奢。設(shè)置好需要暴露的頭文件霎挟,然后用上面的腳步跑一遍。
- 把生成的動(dòng)態(tài)庫(kù)用到項(xiàng)目中麻掸。
之所有沒(méi)有把源碼直接拖到項(xiàng)目中酥夭,嘗試過(guò)但是一拖進(jìn)去就一直保持。后來(lái)用這種方法簡(jiǎn)單粗暴脊奋!