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