大量模塊殼工程本地如何快速編譯?優酷 iOS 工程插件化實踐

語言: CN / TW / HK

作者:醉仙

隨着優酷業務的快速發展,隨之而來的是模塊數量的爆發式增長,基本每年以大量新增模塊的速度增加,到目前為止優酷已經有非常龐大的模塊依賴。模塊之間通信往往是相互直接依賴調用,以至於耦合十分嚴重且混亂,每一個庫依賴都是一顆“樹”,甚至於一張“網”,對日常研發造成很多困擾:

插件化落地結果

iOS模塊插件化已經全面在優酷落地,沉澱出各業務線的輕量工程,大量的業務及架構插件,後續可根據不同業務需求,自由組裝插件工程。以下是目前插件化工程落地後的一些收益:

  • 直接收益

    • 業務插件工程編譯效率提升 顯著,本地編譯時間大幅降低,相關全部開發已使用起來;

    • 通過插件組裝生成業務插件工程,插件工程支持模擬器編譯調試,並支持熱重載;

    • 模塊工程和整包工程均使用插件作為依賴,徹底解決模塊工程和整包工程依賴模塊版本不一致情況,並支持依賴模塊版本自動更新;

    • 業務插件工程依賴庫數量大幅減少,且pod直接複用緩存,大幅提升pod成功率及速度,磁盤佔用大幅減少;

  • 間接收益

    • 可提供運行內存、app啟動、功耗等插件卡口,常態化保持良好的用户體驗;

    • 所有插件支持自由組裝,通過配置中心,提供快速孵化極速版、國際版、Apple Watch、Apple TV等App的能力;

    • 依賴減少,swift斷點調試時的module樹快速生成,斷點效率提升;

    • 提速打包效率,建立插件工程構建平台,測試同學使用平台動態配置生成插件組合安裝包即可進行測試。

插件是什麼

  • 插件是由一組模塊聚合而成,同時也可依賴其他插件。在物理上,插件是一個文本描述文件,描述其包含的模塊和插件信息;
  • 插件基於Xcode工程,可獨立編譯並生成App產物,支持多插件自由組合。

簡單插件

一個簡單的插件可以僅由一個模塊組成。

```

圖片庫插件

target 'Plugin' do
#模塊A pod '模塊A','5.9.4' end ```

複雜插件

一個複雜插件可以由一個或多個插件和模塊組成。

```

插件

target 'Plugin' do # 圖片庫插件 plug '1.圖片庫插件'

#webp圖片解析模塊
pod '模塊B','0.1.4' 
#webp基礎模塊
pod '模塊C','1.1.0.1'

end ```

為什麼需要插件

和多個業務團隊同學溝通後,我們發現大部分的業務在功能調試時,往往只關注涉及到自己需要迭代的業務功能,對於其他業務並不關心。於是我們想到可以基於整包工程,裁剪出一個只有單業務功能的APP,這樣編譯速度肯定會有極大的提升。

裁剪APP需要對模塊進行解耦,如果按模塊顆粒度進行解耦,巨量模塊進行解耦人力成本過高,而且過大的改動也會對線上穩定性有較大的影響。於是我們對解耦粒度進行了放大,從模塊解耦粒度放大到以插件為粒度進行解耦,這樣我們只需要解耦插件和插件之間的橫向耦合關係,插件允許向下依賴其他插件,且插件內部模塊也允許相互耦合,這樣極大的的降低解耦的人力成本,也方便後續以插件維度進行依賴關係進行維護。

插件使用規範

插件聚合原則

  • 業務插件:業務模塊按業務功能維度劃分邊界,聚合成業務插件;
  • 通用業務插件:通用業務模塊按業務可複用最小集劃分邊界,聚合成通用業務插件;
  • 架構功能插件:集團中間件模塊、優酷中間件模塊,按功能最小集劃分邊界,聚合成架構功能插件。

插件依賴原則

  • 業務插件不允許橫向依賴其他業務插件,允許依賴下層插件;
  • 架構層插件不允許依賴上層插件,允許依賴下層插件及其他架構插件。

模塊歸屬原則

  • 一個模塊僅能歸屬到一個插件,需要明確模塊的職能;
  • 同一個模塊被多個插件依賴,需要考慮下沉該模塊為插件;
  • 一個模塊可以寫成一個插件。

插件版本原則

  • 每個插件沒有版本的概念;
  • 一個集成區的模塊和版本對應一套插件中的模塊和版本;
  • 一套插件中的模塊和版本默認和線上版本的集成區一致,也可設置並同步到最新集成區或歷史集成區。

插件層級大圖

基於以上插件的概念和使用規範,我們對優酷APP架構進行插件化改造,從集團中間件到業務層,自下而上解耦聚合模塊形成插件,最終沉澱了大量插件和如下層級的APP架構。

  • 業務實現層:對優酷現有的業務進行插件化改造,聚合成多個通用業務插件,通過業務插件和其依賴的通用業務插件、架構功能插件等少量插件,能快速組合出一個輕量級業務APP,用於提升業務Pod速度和開發調試速度;
  • 業務接口層:對優酷現有的業務進行橫向解耦,形成多個業務接口插件,支撐上層業務插件橫向解耦;
  • 通用業務插件:通用業務模塊按業務可複用最小集劃分邊界,聚合成通用業務插件;
  • 架構功能插件:集團中間件模塊、優酷中間件模塊,按功能最小集劃分邊界,聚合成架構功能插件。

低成本管控方案

優酷所有模塊已經完成插件化改造,為了保障在後續版本迭代過程中,防止工程腐化,制定了一套低成本管控方案,可以自動更新插件內容,管控插件依賴關係。

插件自動更新

插件內容主要包括模塊名稱和模塊版本號,每次版本迭代,插件都面臨插件中模塊的新增、刪除、名稱變更、版本變更等問題,優酷每個版本集成大量的模塊,如果全部人工手動維護,成本將非常巨大,所以我們部署了一套自動同步及巡檢服務,主要有以下目的:

  • 插件中新增、刪除模塊自動更新;
  • 插件中的模塊版本號自動變更;
  • 插件內容更新完成自動對所有插件進行編譯巡檢;
  • 如果巡查通過,插件合併到插件工程集成分支提供給業務插件工程使用;
  • 如果巡查失敗,釘釘通知失敗信息(失敗插件名稱、編譯失敗日誌鏈接、插件新增模塊提示)到釘釘羣,方便快速排查問題。

插件依賴管控

我們基於插件的歸屬和層級,抽象出標準的模塊依賴關係數據,然後在模塊構建打包時,增加依賴檢測卡口,在每次模塊構建過程中,執行依賴檢測卡口,只有通過依賴檢測的插件才能打包通過。

結果數據呈現

構建提效

業務插件工程本地編譯效率對比整包工程:

  • 本地編譯效率得到極大的提升,平均提效顯著,本地編譯時間大幅降低,相關全部開發已使用起來。

計算公式:

  • 編譯提效公式:本地編譯提效 = (整包工程構建時長 - 業務插件工程構建時長) / 整包工程構建時長
  • 節約時間公式:每月節約編譯時間(8小時工作日) = 插件工程月編譯次數 * 平均單次編譯節約時間(秒) / (60 * 60 * 8)

模擬器支持

優酷存在部分模塊不支持模擬器,導致優酷整包不支持模擬器,插件化改造後,業務在通過插件組裝自己業務調試工程的時候,剔除這部分不支持模擬器的插件,使得業務插件工程可以使用模擬器進行調試。模擬器優勢:

  • 一個企業號真機調試限制100台設備,而模擬器無限制;
  • 模擬器支持所有iOS系統,針對一些舊系統開發和測試成本低;
  • 模擬器支持熱重載,無需編譯和重新運行,修改代碼保存即生效;
  • 提前適配iOS新機型UI。

磁盤佔用

在模塊插件化改造前,我們只能使用整包工程進行開發,使用整包工程進行日常開發的時候,需要將所有模塊下載,而插件化改造完成後,我們從整包工程拆分出了多個業務插件工程,插件工程的模塊數量相比整包工程大幅減少,插件工程的磁盤佔用相比整包工程大幅減少。下圖是整包工程和部分業務插件工程磁盤大小對比:

內存佔用

插件化可提供運行內存、app啟動、功耗等插件卡口,常態化保持良好的用户體驗,以播放頁的運行內存為例,播放頁有播放器、頁面容器、彈幕、評論等功能,以前是對整個播放頁計算內存值,而現在可以按照細碎的功能來計算內存值,分別得到播放器插件、播放頁容器插件、彈幕插件、評論插件的內存值。

結語

綜上所述,iOS工程插件化是運用分而治之的思想,把一個複雜的App分成多個子App。通過子App可將研發聚焦於需求研發和用户體驗提升上。同時,插件化的拆裝特性也提高了線上可復現問題的排查效率。因此插件化對研發效率以及開發幸福感的提升都是非常有幫助的。

關注【阿里巴巴移動技術】,阿里前沿移動乾貨&實踐給你思考!