大量模組殼工程本地如何快速編譯?優酷 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可將研發聚焦於需求研發和使用者體驗提升上。同時,外掛化的拆裝特性也提高了線上可復現問題的排查效率。因此外掛化對研發效率以及開發幸福感的提升都是非常有幫助的。

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