iOS之性能優(yōu)化·提高App的編譯速度

      網(wǎng)友投稿 976 2025-03-31

      經(jīng)過(guò)多年的開(kāi)發(fā)和迭代,我相信很多的 iOS 項(xiàng)目代碼已經(jīng)達(dá)到幾十萬(wàn)行甚至上百萬(wàn)行的規(guī)模,所使用的 Pod 庫(kù)的數(shù)量可以達(dá)到幾十個(gè)甚至上百個(gè),App Store 安裝包也變得越來(lái)越大,在這么大的項(xiàng)目規(guī)模下,打包和編譯問(wèn)題逐步成為開(kāi)發(fā)團(tuán)隊(duì)一個(gè)躲不過(guò)的痛,嚴(yán)重影響了研發(fā)效率與其他團(tuán)隊(duì)之間的協(xié)作。

      有時(shí)間,一臺(tái)機(jī)器同時(shí)需要承接七八個(gè)項(xiàng)目,多個(gè)分支的打包任務(wù),在有多個(gè)項(xiàng)目同時(shí)打包的情況,尤其顯得力不從心。

      iOS之性能優(yōu)化·提高App的編譯速度

      在硬件資源有限的情況下,并且在無(wú)侵入、無(wú)影響現(xiàn)有的業(yè)務(wù)的前提下,如何解決這些成為擺在團(tuán)隊(duì)面前的難題和迫在眉睫的需求,怎么加快打包速度成為了一個(gè)需要優(yōu)化處理的重要事項(xiàng)。

      CCache 是一個(gè)編譯緩存器,一個(gè)能夠把編譯的中間產(chǎn)物緩存起來(lái)的工具。

      CCache 的原理是通過(guò)把項(xiàng)目的源文件用 ccache 編譯器編譯,然后緩存編譯生成的信息,從而在下一次編譯時(shí),利用這個(gè)緩存加快編譯的速度,目前支持的語(yǔ)言有:C、C++、Objective-C、Objective-C++;

      如下所示,基本就闡述了 CCache 的工作原理:

      在項(xiàng)目中的實(shí)際編譯流程:

      經(jīng)過(guò)在工程的一番嘗試,CCache 確實(shí)在某些方面上極大的提升了出包的速度。很多時(shí)候項(xiàng)目的打包速度的確減少了一半多,能夠給帶來(lái)比較不錯(cuò)的提升,大大加快項(xiàng)目的出包速度。

      CCache 的優(yōu)點(diǎn)如下:

      能滿足追求的無(wú)侵入、無(wú)影響現(xiàn)有的業(yè)務(wù)的要求,無(wú)入侵、且開(kāi)發(fā)人員無(wú)感知。

      確實(shí)能大幅度地提升編譯速度,項(xiàng)目上最快時(shí)提高3倍以上的編譯速度。

      不需要對(duì)項(xiàng)目作出大調(diào)整,只需部署相關(guān)環(huán)境和一些腳本支持。

      不需要改變開(kāi)發(fā)工具鏈。

      同一個(gè)目錄下,CCache 的緩存命中率相對(duì)穩(wěn)定。

      很多時(shí)候開(kāi)發(fā)的過(guò)程中,項(xiàng)目可能會(huì)存在以下問(wèn)題:

      在未有緩存的情況下,首次打包編譯的時(shí)間比原來(lái)的翻近一倍;

      修改一些引用較多的文件(如公共庫(kù)、底層庫(kù)改動(dòng)),容易造成大范圍的緩存失效,速度會(huì)變得比原來(lái)未使用 CCache 時(shí)更慢;

      多個(gè)項(xiàng)目相同的組件不支持緩存共享,有多個(gè)分支打包的需求,修改目錄名稱后,緩存即失效;

      機(jī)器的 CCache 最大的緩存上限約 18GB,且 Debug/Release 區(qū)別緩存,項(xiàng)目會(huì)占用幾個(gè)GB+的緩存,多個(gè)項(xiàng)目、多個(gè)分支很容易超出上限,一臺(tái)機(jī)器同時(shí)支持多個(gè)項(xiàng)目會(huì)觸發(fā) CCache 清緩存;

      對(duì)機(jī)器硬盤讀寫要求高,如不是全部固態(tài)硬盤,速度影響大;

      CCache 不支持 Clang Modules,系統(tǒng)框架例如 AVFoundation、CoreLocation 等, Xcode 不會(huì)再幫你自動(dòng)引入,會(huì)導(dǎo)致編譯失敗;

      CCache 不支持 PCH 文件;

      CCache 目前不支持 Swift。

      使用二進(jìn)制編譯的自研任務(wù),可以更進(jìn)一步提高研發(fā)效率。

      項(xiàng)目使用 CocoaPods 來(lái)管理第三方庫(kù)和私有庫(kù)的依賴,對(duì)大部分項(xiàng)目來(lái)說(shuō)應(yīng)該是標(biāo)配。目前還是純 Objective-C 的項(xiàng)目,有少量 C++,暫沒(méi)有引入 Swift。

      Carthage 可以將一部分不常變的庫(kù)打包成 framework,再引如到主工程,這樣可以減少開(kāi)發(fā)過(guò)程中的編譯時(shí)間。Carthage 可以比較方便地調(diào)試源碼,如果項(xiàng)目大規(guī)模使用 CocoaPods,轉(zhuǎn)用 Carthage 來(lái)做包管理需要做大量的轉(zhuǎn)換工作,變動(dòng)太大,不滿足的無(wú)侵入、無(wú)影響現(xiàn)有的業(yè)務(wù),這個(gè)方案不太適合。

      cocoapods-packager 可以將任意的 pod 打包成 Static Library,省去重復(fù)編譯的時(shí)間,一定程度上可以加快編譯時(shí)間,但是也有自身的問(wèn)題:

      優(yōu)化不徹底,只能優(yōu)化第三方和私有 Pod 的編譯速度,對(duì)于其他改動(dòng)頻繁的業(yè)務(wù)代碼無(wú)能為力;

      私有庫(kù)和第三方庫(kù)的后續(xù)更新很麻煩,當(dāng)有源碼修改后,需要重新打包上傳到內(nèi)部的 Git 倉(cāng)庫(kù);

      過(guò)多的二進(jìn)制文件會(huì)拖慢 Git 的操作速度(目前還沒(méi)部署 Git 的 LFS);

      難以調(diào)試源碼,不共享編譯緩存;

      打包成 Static Library 過(guò)程緩慢,需要通過(guò)pod lint,各個(gè)組件間又層層嵌套依賴,在現(xiàn)有階段來(lái)說(shuō),是難以實(shí)現(xiàn)的。

      Cocoapods-Binary(Cocoapods 官方推薦的二進(jìn)制插件), 是一個(gè)即時(shí)生成二進(jìn)制包并緩存,而非像 CocoaPods-Packager 僅僅針對(duì)單個(gè)私有庫(kù)的。原理是通過(guò) CocoaPods 提供的 pre_install hook 在 pod install 的 prepare 階段攔截到當(dāng)前的 pod install context,進(jìn)而 fork 出一份獨(dú)立的 installer 以完成將預(yù)編譯源碼 clone 至 Pod/_Prebuild 目錄下,同時(shí)也存在幾個(gè)不足之處:

      單私有源,無(wú)法實(shí)現(xiàn)服務(wù)端緩存,在沒(méi)有對(duì)應(yīng)二進(jìn)制包版本時(shí),pod install 后會(huì)額外去做二進(jìn)制包的生成,一定程度上會(huì)影響 pod install的速度;

      開(kāi)發(fā)者切回源碼調(diào)試,二進(jìn)制緩存會(huì)一并清空,需求重新編譯;

      多個(gè)項(xiàng)目、不同分支的相同組件依舊無(wú)法共享;

      只支持 framework,對(duì)項(xiàng)目需要比較大的頭文件引用方式改動(dòng)。

      cocoapods-bin 雙私有源:該插件進(jìn)行二進(jìn)制化的策略是采用雙私有源,即2個(gè)源地址,一個(gè)靜態(tài)服務(wù)器保存預(yù)先打好包的 framework,一個(gè)是保存源碼的服務(wù)地址。它的優(yōu)點(diǎn):

      源碼和二進(jìn)制文件之間可以來(lái)回切換,速度比較快;

      不影響未接入二進(jìn)制化方案的業(yè)務(wù)團(tuán)隊(duì);

      無(wú)二進(jìn)制版本時(shí),自動(dòng)采用源碼版本;

      接近原生 CocoaPods 的使用體驗(yàn)。

      受到 cocoapod-bin 啟發(fā)后,在借鑒它的部分框架下,可以實(shí)現(xiàn)二進(jìn)制輔助插件cocoapods-imy-bin,新增命令和二進(jìn)制源碼調(diào)試能力。

      在 cocoapods-imy-bin 的輔助下,能無(wú)侵入式自動(dòng)化地制作所有符合條件的組件為二進(jìn)制,且對(duì)于頻繁的業(yè)務(wù)組件也能輕松的應(yīng)用上二進(jìn)制組件,無(wú)需多余操作,一切交給 cocoapods-imy-bin 自動(dòng)化運(yùn)行。

      同時(shí)對(duì)于研發(fā)人員,也能提供獨(dú)立的二進(jìn)制組件給研發(fā)人員使用,解決日常的編譯 效率、跑真機(jī)效率低下,被墻等各種問(wèn)題。

      只要能編譯通過(guò),就制作,一次編譯到處使用,無(wú)入侵。即使獨(dú)立的組件庫(kù)編譯不通過(guò),整體項(xiàng)目能編譯通過(guò)也制作。整套環(huán)境下來(lái),可以不讓開(kāi)發(fā)人員改變?cè)瓉?lái)的開(kāi)發(fā)習(xí)慣,不需要改動(dòng)業(yè)務(wù)中相關(guān)的代碼,基本上做到了使用人員無(wú)感知狀態(tài)。

      如下所示:這是打包幾千個(gè)的經(jīng)驗(yàn)得出對(duì)單個(gè)項(xiàng)目編譯時(shí)間大致的曲線圖,這里假設(shè)一臺(tái)機(jī)器只一次只有一次job,Y軸編譯時(shí)間,X軸某次的編譯, 紅色線條表示的是原生(未使用 CCache 和二進(jìn)制組件),黃色線表示使用了CCache,藍(lán)色表示使用了二進(jìn)制組件:

      由圖可以看出來(lái)在無(wú)任何輔助下原生的編譯時(shí)間曲線(紅色)是趨于平緩,在20min上下左右。CCache 和二進(jìn)制第一次在無(wú)任何緩存的情況下,在一定程度上是會(huì)比原生的耗時(shí),CCache 主要耗時(shí)在邊編譯邊緩存項(xiàng)目的編譯產(chǎn)物。二進(jìn)制主要耗時(shí)在編譯完成后,對(duì) .a 編譯產(chǎn)物的組裝和 push 到私有源倉(cāng)庫(kù)的時(shí)間上(這個(gè)跟所采用有關(guān)系,如果沒(méi)有利用Jenkins 編譯后的產(chǎn)物制作二進(jìn)制就不存在)。

      在 CCache 完全命中二進(jìn)制文件完全都存在的情況下,CCache 比原生的提高一倍以上, 二進(jìn)制會(huì)比 CCache 編譯時(shí)間再提高一倍,且穩(wěn)定在2分鐘左右。二進(jìn)制在之后的表現(xiàn)更趨于平穩(wěn),而 CCache 在修改了某個(gè)被引用較多的文件時(shí)、如底層的公共文件后,命中率就會(huì)大大地降低,有時(shí)會(huì)比不用 CCache 更耗時(shí),如#4位置。在 ci 有多個(gè) job 同時(shí)并發(fā)在跑的情況下,由于 CCache 需要對(duì) IO 頻繁地讀寫操作,耗時(shí)表現(xiàn)可能會(huì)更糟糕些。

      二進(jìn)制的編譯時(shí)間相對(duì)平穩(wěn)很多(藍(lán)色曲線),在架構(gòu)強(qiáng)有力的支撐下,劃分出110多個(gè)獨(dú)立組件,每次的打包基本上是就耗在某個(gè)組件的編譯 +archive。如果是某些變更比較頻繁的組件,我們還可以考慮對(duì)顆粒較大組件配上 CCache,做雙層編譯緩存。雙層編譯緩存原理是 Pods 組件庫(kù)無(wú)二進(jìn)制組件采用源碼編譯時(shí),源碼編譯同時(shí)應(yīng)用 CCache 緩存支持,加速源碼組件的編譯。

      同時(shí)組件庫(kù)可以配合 Gitlab-Ci 的 runner 的應(yīng)用,每次已提交代碼就觸發(fā)獨(dú)立組件的制作二進(jìn)制,讓每次的編譯速度都達(dá)到最快,藍(lán)色二進(jìn)制曲線將會(huì)更接近直線。

      如果存在有獨(dú)立組件無(wú)法編譯問(wèn)題和版本依賴問(wèn)題,也可以再跑個(gè)定時(shí) Job,或者其他輪詢條件 Job,及時(shí)提供最新二進(jìn)制組件。

      一臺(tái)機(jī)器上多個(gè)項(xiàng)目的 CCache 顯得是比較吃力的,且不穩(wěn)定,超出 CCache 的緩存最大值就會(huì)被清掉。使用了二進(jìn)制后,即使是多個(gè)項(xiàng)目編譯時(shí)間都是趨于比較平穩(wěn)的。

      在 Podfile 引入插件后,在 pod install/update 后,符合條件的情況下,會(huì)自動(dòng)轉(zhuǎn)換為二進(jìn)制組件。

      源碼編譯:項(xiàng)目如果上百個(gè) Pods 庫(kù),有 20+ 個(gè)穩(wěn)定 Pods 庫(kù)已經(jīng)被制作為二進(jìn)制庫(kù),并非全部源碼編譯,如何全部轉(zhuǎn)換為源碼編譯,實(shí)際數(shù)字會(huì)比這多出很多。

      在環(huán)境搭建完后,開(kāi)發(fā)人員在 Podfile 中,加入以下兩句,就能享用到自動(dòng)切換為二進(jìn)制組件,體驗(yàn)極速編譯。

      plugin 'cocoapods-imy-bin' use_binaries!

      1

      2

      四、功能點(diǎn)

      目前 cocoapods-imy-bin 插件支持的功能如下:

      無(wú)侵入、無(wú)影響現(xiàn)有的業(yè)務(wù);

      不影響未接入二進(jìn)制化方案的業(yè)務(wù)團(tuán)隊(duì),提供配置文件;

      只要項(xiàng)目能編譯通過(guò)就制作,即使獨(dú)立組件編譯失敗;

      支持無(wú)二進(jìn)制版本時(shí),自動(dòng)采用源碼版本;

      支持只需項(xiàng)目能編譯通過(guò)就能制作二進(jìn)制組件,無(wú)需再關(guān)心 pod lint 等;

      支持 pod bin local 命令一鍵自動(dòng)化制作、上傳、存儲(chǔ)項(xiàng)目本地已經(jīng)存在的二進(jìn)制組件,可配合 ci 打包的編譯產(chǎn)物使用;

      支持指定依賴分支支持:podspec =>’’, :git 方式的引用;

      支持同時(shí) .a、Framework 靜態(tài)庫(kù)產(chǎn)出;

      支持 archive 時(shí),根據(jù) Podfile 自動(dòng)獲取 podsepc 依賴的庫(kù),無(wú)需強(qiáng)制去 spec 倉(cāng)庫(kù)拉取;

      支持多套隔離環(huán)境,如 Debug/Release/Dev 配置,方便為 Debug/Release/Dev 各種環(huán)境提供專用二進(jìn)制組件;

      支持輸出 .a 二進(jìn)制組件制作 binary.podsepc 無(wú)需模板;

      支持穩(wěn)定的二進(jìn)制組件,在上傳二進(jìn)制組件的 binary.podsepc 跳過(guò) pod lint 驗(yàn)證,加快速度;

      支持 pod bin auto 命令一鍵自動(dòng)化制作、上傳、存儲(chǔ)單個(gè)二進(jìn)制組件;

      支持 pod bin auto --all-make 命令一鍵自動(dòng)化制作、上傳、存儲(chǔ)該項(xiàng)目下所有組件的二進(jìn)制組件;

      支持是否使用二進(jìn)制文件、是否制作二進(jìn)制文件和二進(jìn)制/源碼調(diào)試功能的白名單設(shè)置;

      支持 pod install/update 多線程模式,加快 pod 過(guò)程,Pod 速度提升 80%+;

      支持 pod bin install/update 命令,實(shí)現(xiàn)無(wú)入侵修改 Podfile 內(nèi)容,避免直接修改工程的 Podfile 文件而導(dǎo)致提交沖突、誤提交;

      支持 pod bin code 命令,實(shí)現(xiàn)二進(jìn)制庫(kù)不切換源碼庫(kù),程序無(wú)需重新運(yùn)行的調(diào)試能力。

      iOS 移動(dòng)APP

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:甘特圖組件
      下一篇:還有數(shù)據(jù)透視后的匯總數(shù)據(jù)怎么都在數(shù)據(jù)上方了?以前不是在數(shù)據(jù)下方嗎?
      相關(guān)文章
      亚洲AV日韩综合一区| 亚洲第一区视频在线观看| 亚洲国产精品免费在线观看| 亚洲狠狠婷婷综合久久久久| 国产亚洲精品AA片在线观看不加载| 亚洲gay片在线gv网站| 亚洲 日韩 色 图网站| 亚洲毛片基地4455ww| 亚洲资源最新版在线观看| 亚洲一区中文字幕| 亚洲日日做天天做日日谢| 国产成人精品亚洲2020| 久久久久se色偷偷亚洲精品av| 国产精品亚洲精品青青青| 亚洲午夜无码毛片av久久京东热| 亚洲一级免费毛片| 国产精品亚洲片在线va| 亚洲性无码一区二区三区| 亚洲乱妇老熟女爽到高潮的片| 亚洲一卡2卡3卡4卡5卡6卡| 亚洲日韩av无码中文| 亚洲av永久无码精品秋霞电影秋| 亚洲AV无码成人精品区狼人影院| 亚洲?V乱码久久精品蜜桃| 亚洲日韩在线观看| 亚洲精品亚洲人成在线观看| 亚洲AV中文无码字幕色三| 中文字幕亚洲免费无线观看日本| 亚洲福利秒拍一区二区| 亚洲国产成人99精品激情在线| 亚洲制服在线观看| 亚洲日本VA午夜在线影院| AV激情亚洲男人的天堂国语| 亚洲欧洲精品成人久久奇米网 | 亚洲综合色区在线观看| 亚洲精品无码mv在线观看网站| 亚洲国产AV无码专区亚洲AV| 久久久无码精品亚洲日韩按摩 | 亚洲国产精品无码专区在线观看| 亚洲av色福利天堂| 亚洲一区二区三区在线观看蜜桃|