完善 Cocoapods-Binary 支持 Server?端緩存

在開始之前昵慌,還是明確一下我們的目標(biāo),希望通過對 Cocoapods-binary 的改造使其支持 server 端緩存腕唧,從而達到 一處編譯如暖,處處使用 的 pods lib dependencies。同時會簡單對比一下現(xiàn)有已經(jīng)公開的大廠的實踐和利弊橄维,以及我們?yōu)楹芜@么做尺铣。

業(yè)內(nèi)實踐

對于人數(shù)較多的業(yè)務(wù)團隊,為了更好的團隊協(xié)作組件化是不可避免的争舞,關(guān)于如何逐步的組件拆分以及提升編譯美團有一篇不錯的入門 美團外賣iOS多端復(fù)用的推動凛忿、支撐與思考 里面提到了項目的二進制化,但是并沒有涉及如何實現(xiàn)的竞川,更多是關(guān)于如何分步進行組件化迭代店溢。那么如何開始,又有哪些巨人的肩膀可以踩呢委乌?

知乎 iOS 基于 CocoaPods 實現(xiàn)的二進制化方案

知乎的實踐是基于項目工程在提交 PR 后觸發(fā) binary package 的 CI 腳本床牧,相對完整描述了如何進行源碼和 binary 的切換和控制,生成的 binary package 如何在 server 端存儲福澡,還附了基本的流程圖叠赦。總結(jié)一下要點:

  • 通過 YML 配置 binary 白名單革砸、文件服務(wù)配置信息等除秀;
  • 利用libo將xcodebuild后的 dSYM 和 binary 整合(包含了模擬器和真機設(shè)備)后的 ZIP 包上傳至靜態(tài)服務(wù)器,得到對應(yīng)的 URL算利;
  • 利用 CocoaPods Analysis 修改 podSpec 將 binary 為true的庫的 source 指向獲取到的 URL册踩,同時更新 Tag。將修改后的 spec 文件推送至私有倉庫效拭;

分析

  1. 通過 YML 配置來控制源碼和 binary 切換是不錯的方式暂吉,不過如果能基于cocoapod-plugin 插件給 pod DSL 添加 binary 的屬性來控制就更好了。
  2. 對于修改 podspec 以及更新 Private Pod Repo 感覺是有一點冗余的缎患。其實可以在 install 過程中檢查 binary 為 true 的 pod 是否已有打好的 ZIP 包慕的,存在則替換,否則進入 prebuild 流程打包即可挤渔。當(dāng)然這里需要約定好生成的 ZIP 包名肮街,知乎是以 tag + zhihu-static,如/path/to/server/AFNetworking-3.20-zhihu-static判导。本質(zhì)上不論使用哪種方式引用 Pod嫉父,背后對應(yīng)的都是 spec 文件里配置的 source 所指向倉庫中對應(yīng)的一個Git 節(jié)點(PS:每個 commit 對應(yīng)的 hash沛硅,所以管理好版本很重要)。CocoaPods 在解決沖突依賴時绕辖,是依據(jù)語義化版本來遞歸摇肌,所以我認為是不需要單獨對應(yīng)的 static spec。

火掌柜 iOS 端基于 CocoaPods 的組件二進制化實踐

同樣采用雙私有源策略仪际,一個靜態(tài)服務(wù)器保存預(yù)先打好包的 binary围小,一個是源碼服務(wù)地址。區(qū)別于知乎的方案的地方是弟头,他們事先將各個私有庫更新時吩抓,觸發(fā) CI 打包并上傳服務(wù)器,在 pod install 過程中進行替換源赴恨。知乎是在完整項目的構(gòu)建中完成對 binary 的打包和替換疹娶,知乎這樣的一攬子方案才是正解。不過該文章提到不少在實踐中的坑伦连,有比較多的參考意義雨饺,他們還產(chǎn)出了一個 Pod 插件 CocoaPods-bin』蟠荆總結(jié)一下該文章要點:

  • 改造 CocoaPods-Package 额港,支持對單個 pod 進行二進制編譯,打包上傳靜態(tài)服務(wù)器;
  • 基于 Podfile 中添加的全局變量 tdfire_use_source_pods 來控制 binary 白名單歧焦,pod install 時注入環(huán)境變量以控制源碼切換移斩;

分析

  1. CocoaPods-Package 作為官方提供的插件在 1.7.0 正式版發(fā)布后做了一次更新,也是時隔多年绢馍,支持了Swift 的 package 及修復(fù)了一些問題向瓷。以單個 pod 進行二進制編譯的最大麻煩在于,團隊如果進行了比較重度的組件化舰涌,一般會有大量依賴庫需要維護猖任,如果每個庫都需要配置一份 package 腳本成本比較高,同時第三方庫也需要進行鏡像維護瓷耙,盡管支持了 CI 自動化也需要花費一部分精力朱躺,同時業(yè)務(wù)工程師也需要對項目有完整的認知,否則難以捋清其中的關(guān)系搁痛。
  2. 以 IS_SOURCE環(huán)境變量控制 binary 和源碼切換的方式也不是很友好长搀。也是可以給 pod DSL 添加擴展來支持 binary switch。當(dāng)前在每次 install 前加入變量去控制鸡典,使用上感覺有些奇怪盈滴;

改造 CocoaPods-Binary

關(guān)于 Cocoapods-Binary 前段時間寫過一篇簡單介紹,淺析 Cocoapods-Binary 實現(xiàn)。在了解了該插件如何工作之后巢钓,就可以將我們端想法付諸實踐了。
首先疗垛,我們要做的事情很多插件都已經(jīng)幫我們完成了症汹,而我們要做的就是簡單的支持一下對 binary framework 的靜態(tài)服務(wù)器存儲和下發(fā)就好,先來一張流程圖:

image
  • 上圖中的 featch remote framework 和 upload zips to server 就是我們要做的事情贷腕。
    在 Prebuild framework 之前檢查當(dāng)前 pod_target 是否有對應(yīng)的 server cache背镇,存在則 download 至本地同時 unarchive 至 GenerateFramework 文件目錄下,然后跳過當(dāng)前 pod_target 的編譯泽裳。

exist_remote_framewo = sandbox.fetch_remote_framework_for_target(target)

def fetch_remote_framework_for_target(target)
    existed_remote_framework = self.remote_framework_names.include?(zip_framework_name(target))

    return false unless existed_remote_framework

    begin
        zip_framework_path = self.ftp.get(remote_framework_dir + zip_framework_name(target))
    rescue
        Pod::UI.puts "Retry fetch remote fameworks"
        self.reset_ftp
        zip_framework_path = self.ftp.get(remote_framework_dir + zip_framework_name(target))
    end

    return false unless File.exist?(zip_framework_path)

    target_framework_path = generate_framework_path + target.name
    return true unless Dir.empty?(target_framework_path)

    extract_framework_path = generate_framework_path + target.name
    zf = Zipper.new(zip_framework_path, extract_framework_path)
    zf.extract()
    true
end

在 Prebuild 結(jié)束后會進行文件清理和 binary 的替換鏈接瞒斩,在此時進行批量 binary 文件的同步。將GenerateFramework 目錄中所匹配的 pod_target 且資源服務(wù)器所不存在的 binary 文件進行上傳涮总,統(tǒng)一至 static_frameworks 目錄下胸囱,文件名則是 pod_name + tag, 例如 pod 'AFNetworking', '3.0'對應(yīng)的 zip framework 名字為 AFNeworkings-3.0.0.zip 。
sync_prebuild_framework_to_server(target)

def sync_prebuild_framework_to_server(target)
    zip_framework = zip_framework_name(target)
    target_framework_path = framework_folder_path_for_target_name(target.name)
    zip_framework_path = framework_folder_path_for_target_name(zip_framework)

    # ftp server 已有相同 Tag 的包
    return if self.remote_framework_names.include? zip_framework
    # 本地 archive 失敗
    return if !File.exist?(target_framework_path) || Dir.empty?(target_framework_path)

    begin
        Zipper.new(target_framework_path, zip_framework_path).write unless File.exist?(zip_framework_path)
        self.ftp.put(zip_framework_path, remote_framework_dir)
        remote_zip_framework_path = self.ftp.local_file(remote_framework_dir + zip_framework)
        FileUtils.mv zip_framework_path, remote_zip_framework_path, :force => true    
    rescue
        Pod::UI.puts "ReTry To Sync Once"
        self.reset_ftp
        sync_prebuild_framework_to_server(target)
    end
end

實踐過程中瀑梗,為了方便直接是利用了公司現(xiàn)有的 ftp 文件服務(wù)器烹笔,單獨開了一個進行目錄維護。相比 CocoaPods-binary 僅增加了 ftp_tools.rb 和 zip_tools.rb 兩個文件抛丽,實現(xiàn)比較簡單這里就不貼出來了谤职。
限制

  • 最終的 binary size 會比使用源碼的時候大一點,不建議最終上傳 Store 的時候使用亿鲜;
  • 缺少一個驗證的機制允蜈,如果已發(fā)布的二進制包不能被項目正常引用,那么會導(dǎo)致所有人的編譯失斴锪饶套;;
  • 由于工程采用的是全部靜態(tài)庫依賴的形式其馏,所以在二進制和源碼切換的過程中會對 project 文件產(chǎn)生更改凤跑;
  • CocoaPods 在 1.7 以上版本,更改了framework 邏輯叛复,不會把 resource copy 至 framework仔引,因此我們需要將 CocoaPods 版本固定到 1.6.x;
  • 對于動態(tài)配置生成的 framework褐奥,例如RN 相關(guān)的依賴等咖耘,不支持binary;
  • 不同版本 Swift 編譯出的 binary 是不能兼容撬码。如果項目中引用了 Swift 庫Xcode 版本需要統(tǒng)一儿倒。

在使用 binary 的過程中,還有一些意想不到的問題。例如夫否,為了減少源碼和 binary 切換過程中產(chǎn)生的大量 git change彻犁,將 Pods 目錄進行了 ignore,導(dǎo)致工程師在過渡階段切換分支中凰慈,多數(shù)被限制在 pod install 中一些三方庫的 download 上面汞幢,非翻所不能也。還有微谓,在 install 后發(fā)現(xiàn) pod 對應(yīng)的 symbol link 沒有正確生成森篷、對應(yīng)的 source 沒有 copy 成功、業(yè)務(wù) framework 打包耗時超常等一系列問題豺型。

總結(jié)

真實項目實踐中仲智,沒有一勞永逸的辦法。不同的業(yè)務(wù)依賴和環(huán)境配置姻氨,包括工程代碼的規(guī)范钓辆,甚至簡單的頭文件管理都會導(dǎo)致開發(fā)過程產(chǎn)生各種各樣的問題『甙螅總之岩馍,是一個不斷探索和進化的過程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抖韩,一起剝皮案震驚了整個濱河市蛀恩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茂浮,老刑警劉巖双谆,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異席揽,居然都是意外死亡顽馋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門幌羞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寸谜,“玉大人,你說我怎么就攤上這事属桦⌒艹眨” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵聂宾,是天一觀的道長果善。 經(jīng)常有香客問我,道長系谐,這世上最難降的妖魔是什么巾陕? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上鄙煤,老公的妹妹穿的比我還像新娘晾匠。我一直安慰自己,他們只是感情好梯刚,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布混聊。 她就那樣靜靜地躺著,像睡著了一般乾巧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上预愤,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天沟于,我揣著相機與錄音,去河邊找鬼植康。 笑死旷太,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的销睁。 我是一名探鬼主播供璧,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冻记!你這毒婦竟也來了睡毒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤冗栗,失蹤者是張志新(化名)和其女友劉穎演顾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隅居,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡钠至,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胎源。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棉钧。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涕蚤,靈堂內(nèi)的尸體忽然破棺而出宪卿,到底是詐尸還是另有隱情,我是刑警寧澤赞季,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布愧捕,位于F島的核電站,受9級特大地震影響申钩,放射性物質(zhì)發(fā)生泄漏次绘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邮偎。 院中可真熱鬧管跺,春花似錦、人聲如沸禾进。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泻云。三九已至艇拍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宠纯,已是汗流浹背卸夕。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婆瓜,地道東北人快集。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像廉白,于是被迫代替她去往敵國和親个初。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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

  • 涼拌菜有很多種變化,其中一路的關(guān)鍵是拌汁晕讲。拌汁有以醋生變的覆获、有以植物根莖葉的萃取物成秘的、有用鹽和醬油做底的瓢省、有以...
    helloKimmy閱讀 162評論 0 1
  • 作為實小的老師弄息,是幸福的!1月21日至1月23日我們整個科組集體出發(fā)來到了深圳濱海小學(xué)參加黃愛華小學(xué)數(shù)學(xué)精英教師(...
    Sunshine_9aed閱讀 237評論 0 0
  • 在聽別人講大道理的時候勤婚,在聽別人大刀闊斧旁征博引的時候摹量,在聽別人滔滔不絕時,我們中有的人可能會覺得馒胆,他們是夸大其詞...
    樹洞_be61閱讀 206評論 0 0
  • 樓下一個男人病得要死缨称,那間隔壁的一家唱著留聲機,對面是弄孩子祝迂。樓上有兩人狂笑睦尽;還有打牌聲。河中的船上有女人哭著她死...
    種海的玫瑰閱讀 9,935評論 1 2