前言
Pod庫是很重要的組成部分沟优,大部分第三方庫都是通過CocoaPod的方式引入和管理,同時項(xiàng)目中的部分功能也可以用Pod庫來做模塊化睬辐。
本文是對CocoaPod的一些探究挠阁。XS項(xiàng)目中的Pod庫是很重要的組成部分,目前閱讀器模塊正在進(jìn)行SDK化溯饵,需要用Pod庫來管理侵俗,同時未來會做一些模塊化的功能,同樣需要用Pod庫來處理丰刊。
正文
CocoaPods是為iOS工程提供第三方依賴庫管理的工具坡慌,用CocoaPods可以更方便地管理第三方庫:把依賴庫統(tǒng)一放在Pods工程中,同時讓主工程依賴Pods工程藻三。
Pods工程的target是libPods-targetName.a靜態(tài)庫洪橘,主工程會依賴這個.a靜態(tài)庫。 (下面會詳細(xì)剖析這個處理過程)
CocoaPods相比手動引入framework或者子工程依賴的方式棵帽,有兩個便捷之處:
所有Pod庫集中管理熄求,版本更新只需Podfile配置文件;
依賴關(guān)系的自動解析逗概;
同時CocoaPods的使用流程很簡單:(假設(shè)已經(jīng)安裝CocoaPods)
1弟晚、在xcodeproj所在目錄下,新建Podfile文件;
2卿城、描述依賴信息枚钓,以demo為例,有AFNetworking和SDWebImage兩個第三方庫:
target 'LearnPod' do
pod 'AFNetworking'
pod 'SDWebImage'
end
3瑟押、打開命令行搀捷,執(zhí)行pod install ;
4多望、打開生成xcworkspace嫩舟,就可以繼續(xù)開發(fā);
一怀偷、Podfile的寫法
1家厌、普通的寫法;
pod 'AFNetworking' 或者 pod 'AFNetworking', '3.2.1'椎工,前者是下載最新版本饭于,后者是下載指定版本。
2维蒙、指向本地的代碼分支镰绎;
pod 'AFNetworking', :path => '/Users/loyinglin/Documents/Learn/AFNetworking'
指向的本地目錄要帶有podspec文件。
3木西、指定遠(yuǎn)端的代碼分支
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :branch => 'master'
指向的repo倉庫要帶有podspec文件畴栖。
4、針對特定的configurations用不同的依賴庫
pod 'AFNetworking', :configurations => ['Release']`
如上八千,只有Release的configurations生效吗讶;(同理,可以設(shè)置Debug)
5恋捆、一些其他的feature
優(yōu)化pod install速度照皆,可以進(jìn)行依賴打平:將pod庫的依賴庫明確的寫在Podfile.
require "bd_pod_extentions"
bytedanceAnalyzeSpeed(true)
bd_use_app('toutiao','thirdParty','public')
post install的腳本,修改安裝后的Pod庫工程中的target設(shè)置沸停;同理膜毁,可以修改其他屬性的設(shè)置。
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'`
end
end
end
puts只有在添加--verbose參數(shù)可以看到愤钾,Pod::UI.puts則是全文可見瘟滨。
pre_install do |installer|
puts "pre install hook"
Pod::UI.puts "pre install hook puts"
end
Podfile還可以設(shè)置一些警告提示的去除,第一行是去掉pod install時候的警告信息能颁,第二行是去掉build時候的警告信息杂瘸。
# 去掉pod install時候的警告信息
install! 'cocoapods', :warn_for_multiple_pod_sources => false
inhibit_all_warnings
類似的,還有很多其他用ruby去實(shí)現(xiàn)的feature伙菊。
二败玉、Pods目錄
Pods目錄是pod install之后CocoaPod生成的目錄敌土。
目錄的組成部分:
1、Pods.xcodeproj运翼,Pods庫的工程返干;每個Pod庫會對應(yīng)其中某個target,每個target都會打包出來一個.a文件血淌;
2矩欠、依賴庫的文件目錄;以SDWebImage為例六剥,會有個SDWebImage目錄存放文件;
3峰伙、manifest.lock疗疟,Pods目錄中的Pod庫版本信息;每次pod install的時候會檢查manifest.lock和Podfile.lock的版本是否一致瞳氓,不一致的則會更新策彤;
4、Target Support Files匣摘、Headers店诗、Local Podspecs目錄等;Target Support Files里面是一些target的工程設(shè)置xcconifg以及腳本等音榜,Headers里面有Public和Private的頭文件目錄庞瘸,Local Podspecs是存放從本地Pod庫install時的podspec;
三赠叼、CocoaPods的其他重要部分
1.Podfile.lock文件
pod install會解析依賴并生成Podfile.lock文件擦囊;如果Podfile.lock存在時執(zhí)行pod install,則不會修改已經(jīng)install的pod庫嘴办。(注意瞬场,pod update則會忽視Podfile.lock進(jìn)行依賴解析,最后重新install所有的Pod庫涧郊,生成新的Podfile.lock) 在多人開發(fā)的項(xiàng)目中贯被,Pods目錄由于體積較大,往往不會放在Git倉庫中妆艘,Podfile.lock文件則建議添加到Git倉庫彤灶。當(dāng)其他人修改Podfile時,pod install生成新的Podfile.lock文件也會同步到Git批旺。這樣能保證拉下來的版本庫是其他人一致的枢希。
實(shí)際開發(fā)中,也會通過依賴打平來避免多人協(xié)作的Pod版本不一致問題朱沃。
pod install的時候苞轿,Pods目錄下生成一個Manifest.lock文件茅诱,內(nèi)容與.lock文件完全一致;在每次build工程的時候搬卒,會檢查這兩個文件是否一致瑟俭。
2、Pod庫的podspec文件
在每個Pod庫的倉庫中契邀,都會有一個podspec文件摆寄,描述Pod庫的版本、依賴等信息坯门。
如下微饥,是一個普通的Pod庫的podspec:
3、Pod庫依賴解析
CocoaPod的依賴管理相對第三方庫手動管理更加便捷古戴。
在手動管理第三方庫中欠橘,如果庫A集成了庫F,庫B也集成了庫F 现恼,就會遇到庫F符號沖突的問題肃续,需要將庫A/B和庫F的代碼分開,手動添加庫F叉袍;后續(xù)如果庫A/B版本有更新始锚,也需要手動去處理。
而在CocoaPod依賴解析中喳逛,可以把每個Pod庫都看成一個節(jié)點(diǎn)瞧捌,Pod庫的依賴是它的子節(jié)點(diǎn); 依賴解析的過程润文,就是在一個有向圖中找到一個拓?fù)湫蛄小?br>
一個合法的Podfile描述的應(yīng)該是一個有向無環(huán)圖察郁,可以通過拓?fù)渑判虻姆绞剑玫揭粋€AOV網(wǎng)转唉。
按照這個拓?fù)湫蛄兄械捻旤c(diǎn)次序皮钠,可以依次install所有的Pod庫并且保證其依賴的庫已經(jīng)install。
有時候會陷入循環(huán)依賴的怪圈赠法,就是因?yàn)樵谟邢驁D中出現(xiàn)環(huán)麦轰,則無法通過算法得到一個拓?fù)渑判颉?/p>
四、Pods工程和主工程的關(guān)系
在實(shí)際的開發(fā)過程砖织,容易知道Pods工程是先編譯款侵,編譯完再執(zhí)行主工程的編譯;因?yàn)橹鞴こ痰腖inked Libraries里面有l(wèi)ibPods-LearnPod.a的文件侧纯。(LearnPod是target的名字新锈,下面的示例圖都是用LearnPod作為target名)
那么Pod庫中的target編譯順序是如何決定?
打開workspace眶熬,選擇Pods工程妹笆。從上圖分析我們知道块请,主工程最終需要的是libPods-LearnPod.a這一個靜態(tài)庫文件。
我們通常打包拳缠,最終名字都是target的名字墩新;而靜態(tài)庫通常會在前面加上lib的前綴。所以libPods-LearnPod.a這個靜態(tài)庫的target名字應(yīng)該是Pods-LearnPod窟坐。
從下圖我們也可以確定海渊,確實(shí)是在前面添加了lib的前綴。
看看Pods-LearnPod的Build Phases選項(xiàng)哲鸳,從target依賴中可以看到其他兩個target臣疑。
分析至此,我們可以知道這里的編譯順序是AFNetworking徙菠、SDWebImage讯沈、Pods-LearnPod、LeanPod(主工程target)懒豹。
接下來我們分析編譯過程芙盘。AFNetworking因?yàn)闆]有依賴驯用,所以編譯的時候只需要知道自己的.h/.m文件脸秽。
對于Pods-LearnPod,其有兩個依賴蝴乔,分別是AFNetworking和SDWebImage记餐;所以在Header Search Paths中需要設(shè)置這兩個庫的Public頭文件地址。
編譯的結(jié)果是3個.a文件(libPods-LearnPod.a薇正、libAFNetworking.a片酝、libSDWebImage.a),只有l(wèi)ibPods-LearnPod.a是主工程的編譯依賴挖腰。那么libPods-LearnPod.a是否為多個.a文件的集合雕沿?
從libPods-LearnPod.a的大小,我們可以知道libPods-LearnPod不是多個.a的集合猴仑,僅僅是作為主工程的一個依賴审轮,使得Pod庫工程能先于主工程編譯。
那么辽俗,主工程編譯的時候如何去找到AFNetworking的頭文件和.a文件疾渣?
從主工程的Search Paths我們可以看到,Header是有說明具體的位置崖飘;
同時Library也有相對應(yīng)的Paths榴捡,在對應(yīng)的位置放著libAFNetworking.a文件;
這些信息是CocoaPod生成的一份xcconfig朱浴,里面的HEADER_SEARCH_PATHS和LIBRARY_SEARCH_PATHS會指明這兩個地址吊圾。
對于資源文件达椰,CocoaPods 提供了一個名為 Pods-resources.sh 的 bash 腳本,該腳本在每次項(xiàng)目編譯的時候都會執(zhí)行街夭,將第三方庫的各種資源文件復(fù)制到目標(biāo)目錄中砰碴。
CocoaPods 通過一個名為 Pods.xcconfig 的文件來在編譯時設(shè)置所有的依賴和參數(shù)。
在編譯之前會檢查pod的版本是否發(fā)生變化(manifest和.lock文件對比)板丽,以及執(zhí)行一些自定義的腳本呈枉。
Pod庫的子target在指定armv7和arm64兩個架構(gòu)的時候,會分別編譯生成armv7和arm64的.a文件埃碱;然后再進(jìn)行一次合并操作猖辫,得到一個.a文件。
編譯完成后進(jìn)行鏈接砚殿,在armv7和arm64都指定時啃憎,會分別進(jìn)行鏈接,最后合并得到可執(zhí)行文件似炎。
得到可執(zhí)行文件后辛萍,會進(jìn)行asset、storyboard等資源文件的處理羡藐;還會執(zhí)行pod的腳本贩毕,把pod的資源復(fù)制過來。
全部準(zhǔn)備就緒仆嗦,就會生成符號表辉阶,包括.a文件里面的符號。
最后進(jìn)行簽名瘩扼、校驗(yàn)谆甜,得到.app文件。
五集绰、常用Pod指令
pod install规辱,最常用的指令;
pod update栽燕,更新repo并重新解析依賴罕袋;
pod install --repo-update,類似pod update纫谅;
pod install --no-repo-update炫贤,忽略Pod庫更新,直接用本地repo進(jìn)行install付秕;
pod update --no-repo-update兰珍,類似pod install;
pod update AFNetworking询吴,更新指定庫掠河;
以上所有指令都可以添加 --verbose 亮元,查看更詳細(xì)的信息;
xcconfig在新增configuration之后唠摹,需要重新pod install爆捞,并修改xcconfig。
附錄
2021安裝CocoaPods
CocoaPods從安裝到使用
CocoaPods使用總結(jié)
基于 CocoaPods 進(jìn)行 iOS 開發(fā)
pod install vs. pod update
CocoaPods 都做了什么勾拉?
LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 問題+解決過程
pod install 出現(xiàn) connection to github.com:443解決辦法
Failed to connect to github.com port 443: Operation timed out
CDN: trunk URL couldn't be downloaded