一款可能適合你的iOS二進制插件

本文主要內(nèi)容:
一褥伴、背景
二漾狼、效果展示
三、接入插件及demo地址
四似踱、聊聊開發(fā)插件前期的編譯優(yōu)化調(diào)研
五核芽、技術選型后二進制插件的開發(fā)
六酵熙、實際使用后遇到的問題
七绿店、總結
八庐橙、參考文獻

一态鳖、背景

由于團隊也是組件化的開發(fā)模式,而且有較多的app浸须。大的C端產(chǎn)品打包要十幾二十分鐘删窒,小的業(yè)務app打包也要八九分鐘顺囊。那如何提升項目的編譯效率特碳,和打包速度晕换,就是一個需要去處理的課題闸准。這款插件靈活便捷梢灭,可能符合你需要的提效能力或辖。

二颂暇、先看效果

執(zhí)行pod install后的展示


image.png

二進制后工程內(nèi)pod組件結構

image.png

緩存結構目錄


image.png

編譯前后對比


image.png
image.png

具體提效程度看不同工程組件化情況湿蛔,可以拿去到自己項目里感受下阳啥。我們的工程多以OC和OC+Flutter為主财喳,也有集成Swift的組件耳高,還沒有試過純Swift的項目,如果插件使用有問題可以提供demo概荷,我來優(yōu)化下插件碌燕。

三修壕、先去立刻體驗回來再看后續(xù)內(nèi)容

gem install cocoapods-zjbinary

可配合demo工程一起食用,如果插件好用改鲫,可以點個??

https://github.com/Byte10/BinaryDemo

四像棘、聊聊開發(fā)插件前期的編譯優(yōu)化調(diào)研

iOS 微信編譯速度優(yōu)化分享

https://cloud.tencent.com/developer/article/1564372
他們的方案總結是以下:
A缕题、優(yōu)化頭文件搜索路徑
B、關閉 Enable Index-While-Building Functionality
C瘪松、優(yōu)化 PB/模版锨阿,減少冗余代碼
D墅诡、使用 PCH 預編譯
E、使用工具優(yōu)化頭文件引入烟馅;盡量避免頭文件里包含 C++ 標準庫

pod層的優(yōu)化方案:

https://www.dandelioncloud.cn/article/details/1498967543334379522 貝聊科技如何將 iOS 項目的編譯速度提高5倍這片文章郑趁。
他們調(diào)研了下面幾種方案:
1寡润、cocoapods-packager
cocoapods-packager 可以將任意的 pod 打包成 Static Library舅柜,省去重復編譯的時間业踢,一定程度上可以加快編譯時間礁扮,但是也有自身的缺點:
優(yōu)化不徹底太伊,只能優(yōu)化第三方和私有 Pod 的編譯速度,對于其他改動頻繁的業(yè)務代碼無能為力
私有庫和第三方庫的后續(xù)更新很麻煩僚焦,當有源碼修改后,需要重新打包上傳到內(nèi)部的 Git 倉庫
過多的二進制文件會拖慢 Git 的操作速度(目前還沒部署 Git 的 LFS)
難以調(diào)試源碼

2边坤、Carthage
這個方案跟 cocoapods-packager 比較類似谅年,優(yōu)缺點都差不多融蹂,但 Carthage 可以比較方便地調(diào)試源碼缺虐。
因為我們目前已經(jīng)大規(guī)模使用 CocoaPods渐苏,轉用 Carthage 來做包管理需要做大量的轉換工作拆檬,所以不考慮這個方案了洽瞬。

3伙窃、Buck
Buck 是一套通用的構建系統(tǒng),由 Facebook 開源晦闰。最大的特色是智能的增量編譯可以極大地提高構建速度呻右。最早聽說 Buck 的時候鞋喇,它還只能用在安卓上侦香,現(xiàn)在已經(jīng)適配了 iOS。

它能增快構建速度的主要原因是緩存了編譯結果憾赁,通過持續(xù)監(jiān)視項目目錄的文件變化龙考,每次編譯時只編譯有改動的文件晦款。另外一個讓我很受啟發(fā)的功能是 HTTP Cache Server,通過一臺緩存文件服務器來保存大家的編譯結果亡问,這樣只要團隊里其中一人編譯過的文件州藕,其他人就不用再編譯了酝陈,直接下載就行沉帮。

Buck 是個相當完備的解決方案穆壕,很多國外的大公司例如 Uber 都已經(jīng)用上。他們也花了很多時間來研究缨该,最終還是認為對他們的項目和團隊來說贰拿,目前并不是很適合熄云,主要原因是:

Buck 拋棄了 Xcode 的項目文件缴允,需要手工編寫配置文件來指定編譯規(guī)則,這要對現(xiàn)有項目作出大幅度的調(diào)整矗漾。他們目前還在快速迭代新功能,沒有余暇和人手來實施都办。
開發(fā)和調(diào)試的流程都得做出很大的改變。因為 Buck 接管了項目編譯的過程势木,想調(diào)試項目不能簡單地在 Xcode 里面 ?+R 了啦桌,得先反過來讓 Buck 生成 Xcode 的項目文件甫男。Uber 的工程師甚至推薦使用 Nuclide 來代替 Xcode 作為開發(fā)環(huán)境验烧。雖然原理上是可行的碍拆,但是團隊需要花不少時間來適應感混,短期內(nèi)效率降低無可避免。
用 Xcode 調(diào)試代碼享受不到加快編譯速度的好處婆跑。雖然可以用 buck 命令啟動 App洽蛀,然后在命令行里啟動 lldb 來調(diào)試郊供,但那就無法使用 Xcode 的調(diào)試工具 例如 View Debugging 和 Memory Graph Debugger驮审。

4吉执、Bazel
Bazel 跟 Buck 很相似戳玫,是 Google 開源的咕宿,優(yōu)缺點跟 Buck 都差不多,不再詳細說了缆镣。

5董瞻、distcc 分布式編譯
原理是把一部分需要編譯的文件發(fā)送到服務器上钠糊,服務器編譯完成后把編譯產(chǎn)物傳回來。他們嘗試了一下比較出名的 distcc煞聪,搭建過程比較簡單昔脯,最后也能成功地把編譯任務分派到內(nèi)網(wǎng)的多臺服務器上云稚。但是其他編譯服務器的 CPU 占用總是很低静陈,只有 20% 左右诞丽;也就是說分派任務的速度甚至還趕不上服務器編譯的速度僧免,分派任務然后回傳編譯產(chǎn)物這個過程所耗費的時間超過了本地直接編譯懂衩。不停調(diào)整參數(shù)反復試驗了很多次,最后發(fā)現(xiàn)編譯時間完全沒有變快浊洞,甚至還有點變慢了牵敷。可能以他們目前項目的規(guī)模并不適合使用分布式編譯法希。

6枷餐、CCache 是他們最后選擇的方案
大致原理就是將上次的編譯產(chǎn)物緩存起來,在下一次編譯時會檢查是否命中緩存苫亦,如果命中緩存會優(yōu)先取上一次的編譯產(chǎn)物

經(jīng)過在工程中的一番嘗試毛肋,總結出了以下幾個特點

  • CCache 確實能夠很大程度上提高編譯速度
  • CCache 的緩存命中率相對穩(wěn)定
  • CCache 不支持 PCH 文件
  • CCache 不支持 Clang-Moudle 的方式
  • CCache 目前不支持 Swift

7奕锌、最后看到了有贊的二進制方案
https://tech.youzan.com/you-zan-ji-yu-er-jin-zhi-de-bian-yi-ti-xiao-ce-lue/

感覺還是相對契合我們團隊一些,不過沒有開源村生,那我們自己搞下好了。

五饼丘、動手搞二進制插件

Cocoapods-Binary(Cocoapods 官方推薦的二進制插件)他提供了很好的思路趁桃,以及可以教會我如何整一個cocoapods插件。
萬事開頭難肄鸽,這個插件的源碼卫病,已經(jīng)可以讓我開頭了。
經(jīng)過對業(yè)界常用方法的探索典徘,總結出了以下三種二進制化使用的常見方案:

  • 即時生成二進制包并緩存

    類 Carthage 的實現(xiàn)思路蟀苛,以 Cocoapods-Binary(Cocoapods 官方推薦的二進制插件),在 pod install 后逮诲,對本次編譯帜平,即時生成二進制包并緩存,缺點是在沒有對應二進制包版本時梅鹦,pod install 后會額外去做二進制包的生成裆甩,一定程度上會影響 pod install的速度,并且如果開發(fā)者切回源碼調(diào)試齐唆,二進制緩存會一并清空

  • 單私有源嗤栓,PodSpec 包含源碼及二進制信息

    單私有源指的是 Pod 庫均包含在同一個 Repo 內(nèi),二進制的 vendor_libraries / vendor_frameworks 等信息會存在于各個 Pod庫對于 PodSpec 的 SubSpec 中箍邮,在 Podfile 中讀取二進制相關配置去決定是否使用二進制SubSpec

    缺點是源碼與二進制并存與一處茉帅,不僅會讓 PodSpec 顯得臃腫,并且會增大 Source 源的體積锭弊,降低 Pod 庫的 Download 速度以及 Lint 速度堪澎,以及多 SubSpec 的模式也會影響最終生成 xcworkspace 的速度

  • 多私有源

    多私有源指的是源碼與二進制分別獨立,使用兩個不同的 Source廷蓉,二進制文件一般壓縮存于靜態(tài)服務器中全封,以空間去換取時間效率,同時存在的問題是桃犬,Source 之間的切換問題刹悴,二進制包以及 Spec 的生成時機問題

那結合我們團隊現(xiàn)狀,我采取多私有源的方案攒暇,不過不一樣的是土匀,打算將二進制的緩存放在本地,而非服務器中形用,這樣可以做到不依賴服務器就轧,而且省去了制作二進制repo的開發(fā)消耗证杭,只需要本地消耗一些硬盤空間,這對于我們團隊是非常低的成本妒御〗夥撸可以有打包機一次構建后,緩存下來的二進制文件乎莉,同步給開發(fā)同學后送讲,即可省去第一次接入二進制的大部分時間。而且除了緩存機制外惋啃,預期還需要達到以下效果:

  • 開發(fā)同學無需額外改動組件
  • 開發(fā)同學接入無需太多成本
  • 支持源碼切換和調(diào)試
  • 支持部分組件不用二進制
  • 二進制一次編譯后續(xù)直接從緩存讀取

1哼鬓、Cocoapods-Binary接入初體驗

  • pod install 后進行做二進制包的生成,但是只支持framework
  • 開發(fā)者切回源碼調(diào)試边灭,二進制緩存會一并清空异希,重新編譯
  • 由于只支持framework,引入方式變更為 #import <aaa/aaa.h>绒瘦,這個對于我們團隊大部分是以#import "aaa.h"會是個很大的改造量

2称簿、要改造的內(nèi)容

  • 二進制包生成后,添加拷貝到緩存的邏輯
  • 除了framework還支持.a惰帽,就可以解決頭文件引用的問題予跌,目前的項目就不需要大量時間成本進行頭文件引用改造

是不是看起來好像只要改完這兩點就大功告成了,確實是這樣善茎。

3券册、添加編譯成.a的邏輯

二進制包的構建有以下方式

  • cocoapods-packager 插件

cocoapods-packager 是一款開源的二進制打包的 pod 插件,通過源碼 podspec 生成 Podfile垂涯,pod install 生成包含對應 Pod 庫的工程烁焙,之后通過 xcodebuild 去構建 .a / .framework,在看過該庫的源碼后發(fā)現(xiàn)該邏輯并不復雜耕赘,但是在嘗試之后會發(fā)現(xiàn)幾個問題:

當選擇 .a 形式作為產(chǎn)物時骄蝇,我們 podspec 中所指定的 .h 并不會被正確拷貝到目標文件夾
該組件對 Subspec 的處理較為暴力,會將多個 Subspec 合并為一個操骡,例如我一個組件庫九火,Phone 工程需要引用SubSpecA,Pad工程需要引用 SubSpecB册招,在使用該組件打包時岔激,會將 SubSpecA 與 SubSpecB 合并為一個 framework/.a,這種情況顯然不是我們所需要的是掰,更為合理的做法是可通過配置去設置虑鼎,是否將 SubSpec 進行合并或拆分
cocoapods-packager 已經(jīng)停止維護,在對 Cocoapods 新特性或者 Swift 的支持上無法達到同步更新

  • 自行編寫打包腳本只需要使用xcodebild即可
// 構建真機架構
xcodebild -project Pods.xcodeproj -scheme xxx -configuration Release -sdk iphoneos
// 構建模擬器架構
xcodebild -project Pods.xcodeproj -scheme xxx -configuration Release -sdk iphonesimulator

再合成下我們的兩個庫文件

lipo -create '模擬器架構文件' '真機架構文件' -output '目標庫'.a

那至此,我們編譯.a的邏輯就完成了炫彩。

4匾七、添加緩存的邏輯

這個需要在對外提供的屬性添加一個變量,如

set_local_binary_cache_path '/Users/xxx/podBinaryCache'

然后根據(jù)變量設置情況江兢,判斷該組件版本是否在緩存庫里昨忆,不在的話,編譯完二進制后杉允,拷貝一份扔嵌,下次直接從緩存里讀取該組件。
考慮到這個目錄不同電腦上地址取不到夺颤,于是添加了這個屬性,設置二進制默認緩存地址胁勺,開啟后默認地址為:/Users/xxx/Desktop/podCache,方便打包機及團隊內(nèi)同學讀取同一份二進制緩存地址

set_default_desktop_cache_path!  

當然因為有.a和framework的區(qū)別世澜,將緩存添加了區(qū)分分別為library和framework。framework下再區(qū)分靜態(tài)庫和動態(tài)庫署穗。

5寥裂、源碼調(diào)試的邏輯

這個參考了這位大兄弟的思路
https://github.com/Jacky-LinPeng/cocoapods-xlbuild

6、資源的獲取

可以根據(jù)resource_paths拿到這個組件的資源目錄

resources = target.resource_paths
resource_paths = resources[target_name]
resource_paths.each do |path|
  path_names = path.to_s.split('${PODS_ROOT}')
end

六案疲、實際使用后遇到的問題

1封恰、.a的生成要以lib開頭不然會有問題,比如AFNetwroking.a要是libAFNetworking.a

2褐啡、.a以xcodebuild生成后诺舔,沒有頭文件,這沒法用备畦。經(jīng)過一段時間的分析低飒,找到了這個屬性,這里面的東西不就是我要的頭文件嘛

pod_target_header_mappings = target.header_mappings_by_file_accessor.values
image.png

3、資源文件的問題懂盐,處理資源文件需要放入組件文件夾中
1)如果組件本身包含bundle文件褥赊,直接拷貝進去
2)如果組件本身資源文件在assets中莉恼,則打包后尿背,拷貝bundle文件放入

4残家、處理本地pod導入問題
本地引入組件會有Local Podspecs 需要提前在Pods/ 中生成該文件夾茴晋,然后拷貝才不會有問題

5、文件目錄帶有空格符號的問題
處理路徑的時候加了.shellescape即可解決

七烁涌、總結

處理完那些問題后撮执,這個二進制插件基本運行沒有什么問題了,也打到了前面提到的幾個預期谋币,在團隊中至今也穩(wěn)定運行了半年,編譯效率確實有不少提升诅蝶。借鑒了不少業(yè)內(nèi)大佬的經(jīng)驗,嘗試了不少編譯優(yōu)化方案筐眷,學習了ruby插件的開發(fā),解決了一些使用上遇到的問題武翎,熟悉了iOS庫文件的相關知識和cocoapods的源碼,后續(xù)將分享靜態(tài)庫垫毙、動態(tài)庫的學習經(jīng)驗综芥。關于cocoapods插件的學習屠阻,大家可以看下cocoapods-binary的源碼额各。

具體的使用方法都在這里了虾啦,好用的話可以點下?? 謝謝!

https://github.com/Byte10/BinaryDemo

掘金地址:https://juejin.cn/post/7188803862612934713

八需频、參考文獻

https://cloud.tencent.com/developer/article/1564372

https://www.dandelioncloud.cn/article/details/1498967543334379522

https://tech.youzan.com/you-zan-ji-yu-er-jin-zhi-de-bian-yi-ti-xiao-ce-lue/

https://github.com/Jacky-LinPeng/cocoapods-xlbuild

https://github.com/leavez/cocoapods-binary

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藐守,一起剝皮案震驚了整個濱河市卢厂,隨后出現(xiàn)的幾起案子任内,更是在濱河造成了極大的恐慌死嗦,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骡澈,死亡現(xiàn)場離奇詭異,居然都是意外死亡护锤,警方通過查閱死者的電腦和手機官地,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烙懦,“玉大人驱入,你說我怎么就攤上這事÷任觯” “怎么了亏较?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掩缓。 經(jīng)常有香客問我雪情,道長,這世上最難降的妖魔是什么你辣? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任巡通,我火速辦了婚禮,結果婚禮上舍哄,老公的妹妹穿的比我還像新娘宴凉。我一直安慰自己,他們只是感情好表悬,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布弥锄。 她就那樣靜靜地躺著,像睡著了一般蟆沫。 火紅的嫁衣襯著肌膚如雪叉讥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天饥追,我揣著相機與錄音图仓,去河邊找鬼。 笑死但绕,一個胖子當著我的面吹牛救崔,可吹牛的內(nèi)容都是我干的惶看。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼六孵,長吁一口氣:“原來是場噩夢啊……” “哼纬黎!你這毒婦竟也來了?” 一聲冷哼從身側響起劫窒,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤本今,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后主巍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冠息,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年孕索,在試婚紗的時候發(fā)現(xiàn)自己被綠了逛艰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搞旭,死狀恐怖散怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肄渗,我是刑警寧澤镇眷,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站翎嫡,受9級特大地震影響欠动,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钝的,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一翁垂、第九天 我趴在偏房一處隱蔽的房頂上張望铆遭。 院中可真熱鬧硝桩,春花似錦、人聲如沸枚荣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽橄妆。三九已至衙伶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間害碾,已是汗流浹背矢劲。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留慌随,地道東北人芬沉。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓躺同,卻偏偏與公主長得像,于是被迫代替她去往敵國和親丸逸。 傳聞我的和親對象是個殘疾皇子蹋艺,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容