美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染

Graver 是一款高效的 UI 渲染框架,它以更低的資源消耗來構建十分流暢的 UI 界面。Graver 獨創性的採用了基於繪製的視覺元素分解方式來構建界面,得益於此,該框架能讓 UI 渲染過程變得更加簡單、靈活。目前,該框架已經在美團 App 的外賣頻道、獨立外賣 App 核心業務場景的大多數業務中進行了應用,同時也得到美團外賣內部技術團隊的認可和肯定。


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


App 渲染性能優化是一個普遍存在的問題,為了惠及更多的前端開發同學,美團外賣 iOS 開發團隊將其進行開源,Github 項目地址與使用文檔詳見:https://github.com/Meituan-Dianping/Graver 。我們希望該框架能夠應用到更廣闊的業務場景。當然,我們也知道該框架尚有待完善之處,也希望能與更多技術同行一起交流、探討、共建。

前言

我們為什麼需要關注界面的渲染性能?App 使用體驗主要包含產品功能、交互視覺、前端性能,而使用體驗的好與壞,直接影響用戶持續使用還是轉而使用其他 App,所以我們非常關注 App 的渲染性能。而且在互聯網產品流量競爭愈發激烈的大背景下,優質的使用體驗可以為現有用戶提供更好的服務,進而提高用戶轉化和留存,這也意味著創收、盈利。


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖1 使用體驗與轉化、留存

背景

美團外賣 App 從2013年成立至今,已經走過了五個春秋,在技術層面先後經歷了快速驗證、模塊化、精細化和平臺化四個階段,產品形態上也日趨成熟。在此期間,我們構建並完善了監控、報警、容災、備份等各項基礎設施,Metrics 即是其中的性能監控系統。

曾經一段時間,我們以外賣 App 首頁商家卡片列表為例,通過 Metrics 性能監控系統發現它在 FPS、CPU、Memory 等方面的各項指標並不理想。於是,通過 Xcode 自帶的 TimeProfile 等性能檢測工具,然後結合代碼分析等手段找到了現存性能瓶頸。與此同時,我們梳理其近半年的迭代版本需求發現,UI往往需要根據不同場景甚至不同用戶展示不同的內容。為了不斷迎合用戶的需求,快速應對市場變化,這種特徵還會持續存在。然而,它會帶來以下問題:

  • 視圖層級愈加複雜、視圖數量愈加眾多,從版本長期迭代來看是潛在的性能瓶頸點。
  • 如何快速、高效支撐UI變化,同時保證不會二次引入性能瓶頸。


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖2 影響渲染性能、研發效率的瓶頸點

Graver 介紹

為了解決現存的性能瓶頸以及後續潛在的性能瓶頸,我們期望構建一套解決方案,該方案能在充分滿足外賣業務特徵的前提下,以標準化、一站式的方式解決 iOS 端 App 的渲染性能問題,並且對研發效率有一定提升, Graver(雕工)框架應運而生。

因為 Graver 獨創性地採用了全新的視覺元素分解思路,所以該框架使用起來十分靈活、簡單。我們先來看一下 Graver 的主要特點:

性能表現優異

以外賣 App 首頁商家列表為例,應用 Graver 之後5分位滾動幀率從滿幀的84%提升至96%,50分位幾乎滿幀;CPU 佔用率下降了近6個百分點,有效提升了空閒 CPU 的資源利用率,降低了峰值 CPU 的佔用率。如圖3所示:


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖3 優化前後技術指標對比


“一站式”異步化

Graver 從文本計算、樣式排版渲染、圖片解碼,再到繪製,實現了全程異步化,並且是線程安全的。使用 Graver 可以一站式獲得全部性能優化點,可以讓我們:

  • 不再擔心散點式的“遇見一處改一處”的麻煩。
  • 不再擔心離屏渲染等各種可能導致性能瓶頸的問題,以及令人頭痛的解決辦法。
  • 不再擔心優化會有遺漏、優化不到位。
  • 不再擔心未來變化可能帶來的任何性能瓶頸。

性能消耗的“邊際成本”幾乎為零

Graver 渲染整個過程除畫板視圖外完全沒有使用 UIKit 控件,最終產出的結果是一張位圖(Bitmap),視圖層級、數量大幅降低。以外賣 App 首頁鉑金展位視圖為例,原有方案由58個控件、12層級拼接而成;而應用 Graver 後僅需1個視圖、1級層級繪製而成。 伴隨著需求迭代、視覺元素變化,性能消耗恆屬常數級。如圖4所示:


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖4 外賣 App 鉑金展位應用 Graver 前後對比

渲染速度快

Graver 併發進行多個畫板視圖的渲染、顯示工作。得益於圖文混排技術的應用,達到了內存佔用低,渲染速度快的效果。由於排版數據是不變的,所以內部會進行緩存、複用,這又進一步促進了整體渲染效率。Graver 既做到了高效渲染,又保證了低時延頁面加載。


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖5 渲染效率說明


以“少”勝“繁”

Graver 重新抽象封裝 CoreText、CoreGraphic 等系統基礎能力,通過少量系統標準圖形繪製接口即可實現複雜界面展示。

基於位圖(Bitmap)的輕量事件交互系統

如上述所說,界面展示從傳統的視圖樹轉變為一張位圖,而位圖不能響應、區分內部具體位置的點擊事件。Graver 提供了基於位圖的輕量事件交互系統,可以準確識別點擊位置發生在位圖的哪一塊“繪製單元”內。該“繪製單元”可以理解為與我們一貫使用的某個具體 UI 控件相對應的視覺展示。使用 Graver 為某一視覺展示添加事件如同使用系統 UIButton 添加事件一樣簡單。

全新的視覺元素分解思路

Graver 一改界面編程思路,與傳統的通過控件“拼接”、“添加”,視圖排列組合方式構建界面不同,它提供了靈活、便捷的接口讓我們以“視覺所見”的方式構建界面。這一特點在下文Graver使用中詳細闡述,正是因為該特點實現了研發效率的提升。

Graver 使用

Graver 引入了全新的視覺元素分解的思路。藉助該思路可以實現通過一種對象來表達任一視覺元素、甚至是任一視覺元素的組合,從而消除界面佈局的複雜性。

我們先來回顧下傳統界面的構建方式,以外賣 App 商家卡片其中一種樣式為例,如圖6所示:


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖6 外賣 App 商家卡片

在實現商家卡片的界面樣式時,通常會根據視覺上的識別、交互要求來建立界面展示與系統提供的 UI 控件間的映射關係。以標號②位置的樣式為例,在考慮複用的情況下通常這部分會使用三個系統控件來完成,分別是左側藍底的“預訂”使用 UILabel 控件、右側的藍色邊框“2.26.21:30起送”使用 UILabel 控件、把左右兩側 UILabel 控件裝起來的 UIView 控件;在確定好採用的 UI 控件之後,需要針對展示樣式分門別類的設置各個控件的渲染屬性來實現圖示 UI 效果,渲染屬性通常一部分預設,一部分根據業務數據的不同再進行二次設置;其次,設置各個控件的內容屬性實現業務數據內容的展示,展示的內容一般是網絡業務數據經邏輯處理、加工後的數據。如果涉及到點擊事件,還需要添加手勢或者更換成 UIButton 控件。接下來,需要根據視覺要求實現排版邏輯,以標號⑧⑨為例,當標號⑧位置的數據沒有的情況下,需要上提標號⑨位置的“美團專送”到圖示標號⑧位置。諸如類似的排版邏輯隨處可見。對於圖示任一位置的展示內容都存在上述的循環思考、編寫工作。隨著界面元素的增加、變化,問題會變得更加複雜。

傳統的界面構建方式其實是在UI控件的維度去分解視覺元素,具體是做以下四方面的編寫工作:

  • 控件選擇:根據展示內容、樣式、交互要求確定採用哪種系統控件。
  • 佈局信息:UI 控件的大小、位置,即 Frame。
  • 內容信息:UI 控件展示出來的業務數據,如標號①位置的“星巴克咖啡店”。
  • 渲染信息:UI 控件展示出來的效果,如字體、字號、透明度、邊框、顏色等。

最後,將各個控件以排列組合方式合成為一棵視圖樹。

Graver 框架提供了以畫板視圖為基礎,通過對更底層的 CoreText、CoreGraphic 框架封裝,以更貼近“視覺所見”的角度定義了全新視覺元素分解、界面展示構建的過程。

通常“視覺所見”可劃分為兩部分:靜態展示、動態展示。靜態展示包含圖片、文本;動態展示包含視頻、動畫等。在視覺展示全部為靜態內容的時候,一個 Cell 即是一個畫布,除此以外沒有任何 UI 控件;否則,可以按需靈活的進行畫布拆分來滿足動畫、視頻等需要。


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖7 畫板和傳統視圖樹


以圖6商家卡片中標號②⑧為例,新實現方式的偽代碼是這樣的:


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


上述實現方式即是把標號②⑧部分作為一個整體來實現,任何單一系統控件都無法做到這一點。

Graver 渲染原理


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖8 Graver 工作時序


如圖8所示,Graver 涉及多個隊列間的交互,以外賣App商家列表為例,整體流程如下:

  • 主線程構建請求參數,創建請求任務並放入網絡線程隊列中,發起網絡請求。
  • 網絡線程向後端服務發起請求,獲得對應的業務模型數據(如包含了店鋪名稱,商家頭圖,評分,配送時長,客單價,優惠活動等店鋪屬性的商家卡片列表)。
  • 網絡線程創建包含業務模型數據(如商家卡片列表)的排版任務,提交到預排版線程處理,進入預排版流程。預排版隊列取出排版任務,交由佈局引擎計算UI佈局,將業務模型解析成可被渲染引擎直接處理的,包含佈局、層級、渲染信息的排版模型。解析結束後,通知主線程排版完成。
  • 主線程獲取排版模型後,隨即觸發內容顯示。根據相對屏幕位置及出現的先後順序,創建包含將需要顯示區域信息的繪製任務,放入異步繪製線程隊列中,發起繪製流程。
  • 異步繪製線程隊列取出繪製任務,進行圖文繪製,最終輸出一張包含了圖文內容(如商家卡片)的圖片。繪製任務結束後,通知主線程隊繪製完成,主線程隨後展示繪製區域。

整體按照隊列間串行、隊列內並行的方式執行。

業務應用

Graver 在外賣內部發布之後,我們也將其推廣到更多的業務線,並希望 Graver 能夠成為對業務開展有重要保障的一項基礎服務。經過半年多的內部試用,Graver 的可靠性、渲染性能、業務適應能力也受到外賣內部的肯定和認可。截止發稿時,Graver 已經基本覆蓋了美團App的外賣頻道、獨立外賣App核心業務場景的大多數業務。下面列舉 Graver 在外賣業務的部分應用案例:


美團開源Graver框架:用“雕刻”詮釋iOS端UI界面的高效渲染


圖9 Graver 業務應用

經驗總結

總結一下,對於界面渲染性能優化而言,要站在一個更高角度來思考問題的解決方案。橫向上,從普適性角度解決性能瓶頸點,避免其他人遇到類似問題的重複工作;縱向上,從長遠考慮問題做到防微杜漸,一次優化,長期受益。基於此,我們提出一站式、標準化的渲染性能解決方案。誠然,這會遇到很多難點。面對界面樣式構建的問題,系統 UIKit 框架著實為我們提供了便利,然而有時候我們需要跳出固有思維,嘗試建立一套全新界面構建、視覺元素分解的思路。

洋洋,美團高級工程師。2018年加入美團,目前負責【美團外賣】和【美團外賣頻道】的 iOS 客戶端首頁業務,以及支撐首頁業務的技術架構、工具和系統的開發和維護工作。

歡迎加入美團開源框架Graver技術交流群,跟項目維護者零距離交流。進群方式:請加美美同學微信(微信號:

MTDPtech02),回覆:Graver,美美會自動拉你進群。


分享到:


相關文章: