iOS 原生渲染與 Flutter 有什麼區別 (下)

語言: CN / TW / HK

theme: smartblue

「這是我參與2022首次更文挑戰的第20天,活動詳情檢視:2022首次更文挑戰」。

在上篇文章「iOS 原生渲染與 Flutter 有什麼區別 (上)」中,我們瞭解了渲染原理以及原生渲染的流程,在這篇文章中,我們來聊聊Flutter是如何渲染,以及前端是如何在iOS上渲染。

Flutter 渲染

Flutter 介面是由 Widget 組成的,所有 Widget 組成 Widget Tree,介面更新時會更新 Widget Tree,然後再更新 Element Tree,最後更新 RenderObject Tree

接下來的渲染流程,Flutter 渲染在 Framework 層會有 BuildWiget TreeElement TreeRenderObject TreeLayoutPaintComposited Layer 等幾個階段。將 Layer 進行組合,生成紋理,使用 OpenGL 的介面向 GPU 提交渲染內容進行光柵化與合成,是在 FlutterC++ 層,使用的是 Skia 庫。包括提交到 GPU 程序後,合成計算,顯示螢幕的過程和 iOS 原生基本是類似的,因此效能也差不多。 Flutter在緩衝策略上與 iOS原生稍有不同的是:

Flutter 使用的是 VSync + 三重緩衝 (Triple Buffering),在iOS原生 使用的是 VSync + 雙重緩衝 (Double Buffering)

Untitled-2022-02-25-1647.png

渲染管道

Flutter 渲染管道涉及到多重步驟:

  1. 首先得到使用者的輸入,例如觸控式螢幕幕事件,一些動畫可能會隨之產生,然後開始構建元件並去渲染它們;
  2. 渲染可以細分為3個子步驟;
    1. Layout(佈局),它的作用是在螢幕上確定每個元件的大小和位置;
    2. Paint(繪製),它提供一系列方法把元件渲染成使用者看到的樣子;
    3. Composite(圖層合成)它把繪製步驟生成的圖層或者紋理堆疊在一起,按照順序組織它們,以便它們可以高效的在螢幕上進行呈現,圖層合成是元件最終呈現在螢幕上之前很關鍵的也是最後的一個優化步驟;
  3. 最後是光柵化,它把抽象的表現對映成物理畫素顯示在螢幕上。

Untitled-2022-02-20-2256.png

前端 渲染

前端大部分都是使用WebKit框架下的WebViewWebView 需要額外解析 HTML + CSS + JavaScript 程式碼,首次內容載入時, WebView 會比原生渲染慢。

除了首次載入解析要耗時,以及 JavaScript 語言本身解釋慢導致的效能問題外,WebView 的渲染程序是單獨的,每幀的更新都要通過 IPC 呼叫 GPU 程序。頻繁的 IPC 程序通訊也會有效能損耗。

WebView 的單獨渲染程序還無法訪問 GPU 的 context,這樣兩個程序就沒有辦法共享紋理資源。紋理資源無法直接使用 GPU 的 Context 光柵化,那就只能通過 IPC 傳給 GPU 程序,這也就導致 GPU 無法發揮自身的效能優勢。由於 WebView 的光柵化無法及時同步到 GPU,滑動時容易出現白屏。

寫在最後

相比較,不難發現其實Flutter某些層面上可能表現和原生不相上下,某些層面甚至是超越,相比較而言,由於WebView渲染層級多,限制多,計算多,所以在效能和速度方面還是要弱於原生和Flutter