iOSPlayground.xcodeproj | 殼工程,包含 App Target:iOSPlayground | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
iOSPlayground | 殼工程文件目錄,包含資源、代碼、Info.plist | ||||||||||||||||||||||||||||||||||||||
Podfile | 聲明 User Target 的依賴 | ||||||||||||||||||||||||||||||||||||||
Gemfile | 聲明 CocoaPods 的版本,這裏是 1.7.5"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們在 Podfile 中爲 Target「iOSPlayground」引入 SDWebImage 以及 SDWebImage 的兩個 Coder,並聲明這些組件的版本約束"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"platform :ios, '11.0'\nproject 'iOSPlayground.xcodeproj'\ntarget 'iOSPlayground' do\n pod 'SDWebImage', '~> 5.6.0'\n pod 'SDWebImageLottieCoder', '~> 0.1.0'\n pod 'SDWebImageWebPCoder', '~> 0.6.1'\nend\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後執行 Pod install 命令 "},{"type":"codeinline","content":[{"type":"text","text":"bundle exec pod install"}]},{"type":"text","text":",CocoaPods 開始爲你構建多依賴的開發環境;整個 Pod Install 流程最核心的就是 "},{"type":"codeinline","content":[{"type":"text","text":"::Pod::Installer"}]},{"type":"text","text":" 類,Pod Install 命令會初始化並配置 Installer,然後執行 install! 流程,install! 流程主要包括 6 個環節"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/09\/090c4ec86bd7ba3e1fc9d4f87e5deee8.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"def install!\n prepare\n resolve_dependencies # 依賴決議\n download_dependencies # 依賴下載\n validate_targets # Pods 校驗\n generate_pods_project # Pods Project 生成\n if installation_options.integrate_targets?\n integrate_user_project # User Project 整合\n else\n UI.section 'Skipping User Project Integration'\n end\n perform_post_install_actions # 收尾\nend\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面會對這 5 個流程做一些簡單分析,爲了簡單起見,我們會忽略一些細節。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"準備階段"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個流程主要是在 Pod Install 前做一些環境檢查,並且初始化 Pod Install 的執行環境。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/78\/786a85db421a8212cf846b93d610893a.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"依賴分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個流程的主要目標是分析決議出所有依賴的版本,這裏的依賴包括 Podfile 中引入的依賴,以及依賴本身引入的依賴,爲 Downloader 和 Generator 流程做準備。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/02\/027cc9f00a195fb330722934da446c5c.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個過程的核心是構建 Molinillo 決議的環境:準備好 Specs 倉庫,分析 Podfile 和 Podfile.lock,然後進行 Molinillo 決議,決議過程是基於 DAG(有向無環圖)的,可以參考下圖,按照最優順序依次進行決議直到最後決議出所有節點上依賴的版本和來源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/f7\/f7972a700bb8f7b126e2d059b8a3beba.gif","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"iOSPlayground 工程最後決議出的依賴列表是:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/20\/209d1ba49b70a7122c010c6ef0d719aa.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於最後決議的結果我們就可以獲取 Specifications、生成 Aggregate Targets 和 Pod Targets。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Aggregate Targets:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a0\/a04f1485c9fe25ae4c3d34afa6837376.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Pod Targets:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/7f\/7feb5200211900c251ee6f9e280e6fcd.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"
|
抖音研發效能建設 - CocoaPods 優化實踐
{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"抖音很早就接入 CocoaPods 進行依賴管理了,項目前期抖音只有幾十個組件,業務代碼也基本在殼工程內,CocoaPods 可以滿足業務研發的需求,但是隨着業務的不斷迭代,代碼急劇膨脹,同時抖音工程也在進行架構優化,比如工程組件化改造,組件的數量和複雜度不斷增加:組件(Pod)數量增加到 400+ ,子組件(Subspec)數量增加到 1500+ ,部分複雜組件的描述文件(podspec)膨脹到 1000+ 行,這導致了依賴管理流程(主要是 Pod Install)的效率不斷下降,同時也導致了 Xcode 檢索和構建效率下降。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了效率下降外,我們也開始遇到一些 CocoaPods 潛在的穩定性問題,比如在 CI\/CD 任務併發執行的環境下 Pod Install 出現大量失敗,這些問題已經嚴重影響了我們的研發效率。在超大工程、複雜依賴、快速迭代的背景下,CocoaPods 已經不能很好地支撐我們的研發流程了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"反饋最多就是 Pod Install 慢,經常會有同學反饋 Pod Install 流程慢,涉及到決議流程慢,依賴下載慢、Pods 工程生成慢等"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"本地 Source 倉庫沒更新,經常導致找不到 Specification,Pod Install 失敗"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"依賴組件多,循環依賴報錯,但是難以找到循環鏈路"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"依賴組件多,User 工程複雜度,導致 Pod Install 後 Xcode 工程索引慢,卡頓嚴重"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"依賴組件多,工程構建出現不符合預期的失敗問題,比如 Arguments Too Long"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"研發流程上,有部分研發同學本地誤清理了 CocoaPods 緩存,導致工程編譯或者鏈接失敗"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"text","text":"組件拆分後,新添加文件必須 Pod Install 後纔可以被其他組件訪問,這拖慢了研發效率"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們開始嘗試在 0 侵入、不影響現有研發流程的前提下,改造 CocoaPods 做來解決我們遇到的問題,並且取得了一些收益。在介紹我們的優化前,我們會先對 CocoaPods 做一些介紹, 我們以 CocoaPods 1.7.5 爲例來做說明依賴管理的核心流程「Pod Install」"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Pod Install"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們以一個 MVP 工程「iOSPlayground」爲例子來說明,iOSPlayground 工程是怎麼組織的:"}]},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.