🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

Flutter 的真正價值是什麼?深度解析再結合鴻蒙,告訴你 Flutter 的真正優勢

這會是一篇幫你深入理解 Flutter 真正優勢的內容,同時也解釋了:為什麼 Flutter 在鴻蒙這個全新平台上適配可以完成得那麼快

內容較長,不建議 AI 總結。

其實,一直以來 Flutter 的最大的優勢都不是它的上層 UI,而是它的底層 Embedder,就像 KMP 最大的優勢是 Kotlin 的強大的編譯器支撐一樣,Flutter 的最大價值其實是它的 Flutter Embedder:通過 Embedder 你可以在任何「非官方」平台跑起來 Flutter

這也是為什麼 Flutter 會是鴻蒙最早發布的跨平台框架,這也是為什麼「寶馬」和「豐田」可以在自家車機系統使用 Flutter、LG 的 WebOS 電視系統可以使用 Flutter、Raspberry Pi(樹莓派)和三星 Tizen 等 IoT 也使用 Flutter 的根本原因。

當然,這個場景對於一般的應用開發者來說難度較高,因為 Embedder 的 API 雖然穩定,但 API 很底層,不適合新手直接從零開始,所以它更多體現在企業價值,比如最近的豐田進一步開發 Flutter,推出全新 3D 遊戲引擎 Fluorite這種情況,它的價值在於為企業提供一套成熟的可遷移渲染架構支持

Flutter Embedder

那所謂的 Flutter Embedder 它到底“嵌入”了什麼?

簡單來說,Flutter 的 Engine 通常以動態庫形式交付,而對外提供一個穩定 ABI 的 C 接口,所以真正把 Flutter 跑起來的,是平台側那層很薄的 Embedder,你可以這麼理解:

  • Flutter Engine:Dart VM + 渲染管線(Skia/Impeller 等)、文本排版、動畫、合成、語義(無障礙)等「UI 引擎本體」

  • Embedder:負責把引擎接到真正的設備層,包括圖形上下文/交換鏈、輸入事件、VSync、線程模型、文件與資源、平台消息通道(platform channel)、可選的外部紋理/原生視圖合成等。

為了確保 Embedder 與 Engine 版本之間的解耦,Flutter 定義了一套嚴格的 ABI 規則,所有的配置信息通過 embedder.h 中的結構體進行傳遞,而這些結構體的新成員只能添加在末尾,且每個結構體的第一個成員必須是 size_t struct_size 的存在,這種設計讓 Engine 可以在運行時根據傳入的大小判斷 Embedder 支援的 API 版本,從而實現向前和向後兼容。

image

那麼如果使用 Embedder 層,一般需要做什麼?為什麼說它對新手難度比較高?簡單來說,Flutter 的 Embedder 可以按能力分成 6 個部分來理解。

啟動和資源

核心是 FlutterEngineRun(...),它是通用的嵌入層入口,開發者要提供 FlutterRendererConfig(渲染後端配置)和 FlutterProjectArgs(資源、回調、快照等)來滿足 Flutter 運行的環境,例如 FlutterProjectArgs 裡最常見是:

  • assets_path:Flutter 資源目錄
  • icu_data_pathicudtl.dat(國際化/文字相關)
  • platform_message_callback:平台消息回調
  • AOT/JIT 所需的快照相關字段(AOT 需要提供一組 snapshot 指針;JIT 需要 assets 裡有 kernel blob)

渲染

另外就是如何把 Flutter 畫到屏幕上,FlutterRendererConfig 支援多種後端:OpenGL / Vulkan / Metal / Software,一般在第三方平台,最常見的就是 OpenGL,對於 OpenGL 會需要實現一組回調:

  • make_current / clear_current:切換/清理上下文
  • fbo_callback:告訴引擎往哪個 FBO 畫
  • presentpresent_with_info:提交到屏幕(可帶 damage 信息做局部刷新優化)
  • make_resource_current:給後台線程的資源上下文(紋理異步上傳性能很關鍵)

如果還要做更高級的合成(比如硬體 overlay plane、原生視圖/多層合成),還會用到 compositor(FlutterCompositor)接口:引擎把 layer 信息交給平台,平台負責最終上屏合成。

當然,鴻蒙平台現在也已經實現了 Vulkan + Impeller 的默認支援。

線程和任務

如果對應平台,類似嵌入式里經常沒有現成的消息循環模型或者多線程模型,開發者就要提供自己實現的自定義 task runner:

  • FlutterTaskRunnerDescription:至少要實現 post_task_callback
  • FlutterCustomTaskRunners:可分別指定 platform / render task runner(也可以合併到同一線程)

這部分決定了 Flutter 能否穩定跑在設備的主循環(systemd event loop、glib、Qt event loop、裸循環等)上。

VSync

Flutter 引擎還需要在平台 VSync 同步信息來時通知 FlutterEngineOnVsync(...),並且有明確線程要求(必須在調用 FlutterEngineRun 的線程上),沒有正確 VSync,你可能會遇到:

  • 幀率不穩、輸入/動畫延遲
  • 合成節奏和顯示器不同步導致抖動/撕裂風險(取決於你的 present 實現)

這個在一些嵌入式平台確實會有這個問題,所以需要開發者自己處理。

輸入

Embedder 還需要把設備輸入轉成 Flutter 的事件並送入引擎,例如:

  • SendPointerEvent(觸摸/滑鼠)
  • SendKeyEvent(鍵盤)
  • SendWindowMetricsEvent(大小、devicePixelRatio 變化等)

其他

其他的主要看你是否有哪些對應的需要,例如:

  • Platform Channels 交互實現,通過 Platform Channels 把 Dart 端的調用轉成平台端實現(例如電量、藍牙、相機等),在嵌入平台你一樣可以用 platform channels 去封裝 native 能力,在 embedder C API 裡對應的是:

    • 提供 platform_message_callback 接收來自 Dart 的消息
    • 可以向 Dart 回覆 FlutterEngineSendPlatformMessageResponse(...)
  • 外部紋理(External Texture),通常是用於視頻流/相機/解碼器/硬體圖層等,例如:

    • 註冊:FlutterEngineRegisterExternalTexture
    • 有新幀:FlutterEngineMarkExternalTextureFrameAvailable
    • 取消:FlutterEngineUnregisterExternalTexture
  • 無障礙/語義(Semantics),FlutterProjectArgs 裡有語義更新回調,引擎也有啟用/派發語義動作的接口(用於屏幕閱讀、無障礙輸入等)

簡單總結一下,大致有:

API 類別 關鍵函數/結構體 平台對接職責
生命週期管理 FlutterEngineRun, FlutterEngineShutdown 控制引擎的啟動時機與資源回收
渲染配置 FlutterRendererConfig 指定 OpenGL、Vulkan 或軟體渲染的回調函數
消息傳遞 FlutterEngineSendPlatformMessage 實現 Dart 與原生代碼的雙向異步通信
事件注入 FlutterEngineSendPointerEvent 將硬體層產生的觸摸/滑鼠事件轉換為 UI 事件
任務調度 FlutterTaskRunnerDescription 定義任務發布回調,將引擎任務整合進系統事件循環

image

所以,可以看出,從 0 實現一個 Embedder 的工作量還是不小的,但是也可以看出,在這個過程中,你只需要專注於 如何用 Embedder 接口讓 Flutter 成功運行起來,不需要關心 Engine 和 Framework 的相關實現,況且,也沒有讓你真的從 0 開始寫

比如你需要在嵌入式設備上實現 Embedder,而嵌入式上系統大多數時候都是精簡的 Linux 魔改,那麼你完全可以基於 Linux embedded 稍微調整來實現對接即可,比如 flutter-pi 和 Sony 的 flutter-embedded-linux 方向:

flutter-pi 就是 “輕量 Linux Embedded embedder、無需 X11/Wayland”,這種直接渲染模組(DRM)和通用緩衝管理(GBM)實現,通過“直接入屏”的渲染路徑跳過了 X11 或 Wayland 等合成器,可以降低顯存佔用和顯示延遲,非常適合一些嵌入式場景。

Flutter 的 Embedded Linux 就是目前被二次定製最多的 Embedded,特別是它已經有的:

  • 一個可以接入 Wayland 或 DRM 進行渲染的 C++ embedder
  • 集成了 OpenGL 圖形功能
  • 支援觸控屏或遙控器等輸入設備

比如鴻蒙內核,它的內核是兼容 Linux 的,基礎三大件:

  • POSIX 兼容:提供標準的類 Unix 應用程式編程介面,對應的內核抽象層(KAL)+ musl libc 就可以滿足大部分場景
  • ABI:支援預編譯 Linux 二進制程式的執行
  • HDF:實現跨內核、跨平台的驅動開發與複用,支援 Linux 驅動

我們假設不是手機鴻蒙,而是 OpenHarmony,在沒有官方支援的情況下,也可以通過 Linux Embedded 去嘗試接入 Flutter。

當然,如果需要運行的平台真的很特殊,你需要從頭開始,那麼實現路線也很清晰:

  • 首先就是獲得一個可用的 Flutter Engine,也就是能在目標設備上運行的引擎產物(常見是 libflutter_engine.so/類似動態庫 + icudtl.dat 等),一般這種情況下就需要你自己編譯 engine
  • 其次就是實現上面說的 Embedder,例如一個最小可運行的 MVP 大概需要:
    • 實現一個渲染對接,如果是基於 DRM/GBM,需要調用 libdrm 打開顯示節點,通過 libgbm 創建緩衝區,並初始化 EGL Surface,建立 swapchain / framebuffer / surface,實現 FlutterRendererConfig 對應回調和配置
    • 確定 platform channels 模型,提供 TaskRunners,實現一個基於 epollglib 的消息循環,當 Flutter Engine 有任務需要執行時,通過 post_task_callback 通知啟動器,啟動器需將該任務排入系統事件隊列
    • 實現 vsync 對接
    • 實現輸入系統,例如利用 libinput 或驅動,實時獲取事件並調用 FlutterEngineSendPointerEvent
    • 建立 platform message
    • ···

在這方面三星 Tizen 系統的集成也是一個很好的例子,flutter-tizen 的 Embedder 實現,讓開發者能夠利用同一套代碼給三星的電視、冰箱屏幕甚至手錶開發應用。

鴻蒙

當然,要說 Flutter 嵌入層最成功的典型例子,那肯定是鴻蒙 Flutter:華為實現的 flutter_flutter 現在已經有 3.35.7的 dev 分支,也就是 framework 和 engine 已經完全合併的 Monorepo,項目在標準 Flutter 倉庫的基礎上進行了擴展,具體包括:

  • 位於 engine/src/flutter/shell/platform/ohos/ 的 C++ OHOS 平台 shell
  • 位於 engine/src/flutter/shell/platform/ohos/flutter_embedding/ 的嵌入實現
  • packages/flutter_tools/ 中的 OHOS 特定構建命令
  • 引擎 bin/internal/engine.ohos.versionbin/internal/engine.ohos.har.version
  • ····

首先我們前面說的 FlutterEngineRun 是通用 Embedder API,在鴻蒙上會通過 ArkTS -> NAPI -> native 路徑調用,而 FlutterRendererConfig 在鴻蒙上與 XComponent 強綁定,由 XComponentBase 實現具體渲染回;FlutterProjectArgs 中的資源路徑、AOT 數據、任務運行器等會結合鴻蒙文件系統與線程模型配置,通過 FlutterNapi 將 ArkTS 層配置轉換為 native 層 FlutterEngineRun 所需參數:

image

具體層級關係如下圖所示:

image

在這裡,Embedding 的實現具體有:

  1. FlutterAbility 繼承自鴻蒙的 UIAbility,是獨立頁面的入口,主要負責:
    • 持有並初始化 FlutterAbilityAndEntryDelegate (包括 doInitialFlutterViewRun() 、生命週期映射和 FlutterEngineCacheFlutterEngineGroup 等邏輯)
    • 向下轉發所有系統生命週期事件

而這裡 FlutterEngine 就是 Flutter 在 Embedding 的 ArkTS 執行環境的實現,管理所有系統通道和插件,主要包括:

  • LifecycleChannel:應用生命週期
  • NavigationChannel:路由導航
  • TextInputChannel:文字輸入
  • PlatformChannel:平台能力
  • SettingsChannel:系統設置(亮度/字體/時鐘格式)
  • LocalizationChannel:國際化/語言
  • AccessibilityChannel:無障礙
  • RestorationChannel:狀態恢復
  • NativeVsyncChannel:原生垂直同步

image

  1. FlutterNapi 是 ArkTS 與 C++ 原生引擎之間的核心溝通實現:
    • ArkTS 層會調用 FlutterNapi.init(),傳入bundlePath(應用包路徑)、appStoragePath(應用存儲路徑)、engineCachesPath(引擎緩存路徑)、args(命令行參數)、initTimeMillis(初始化時間戳)、productModel(設備型號)等參數
    • FlutterNapi.xComponentAttachFlutterEngine()XComponent 和 native Shell 綁定,核心是將 xcomponentIdnativeShellHolderId

一般路徑: engine/src/flutter/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets

  1. 渲染上, FlutterPage 是鴻蒙特有的渲染容器,用 XComponent 作為 Flutter 渲染的承載,FlutterPage.ets 中的 ArkUI XComponent 指定了 libraryname: 'flutter',所以會加載 libflutter.so 並觸發 library_loader.cpp 中的 NAPI 註冊:

image

然後每個 Flutter 實例對應一個 OHOSShellHolder,持有完整的 Flutter Shell:ohos_shell_holder,OHOS 通過自己的抽象層(OHOSContext/OHOSSurface)和 NAPI 橋接,不直接構造 FlutterRendererConfig,而是由 PlatformViewOHOSCreateRenderingSurface() 返回對應的 SurfaceCreateOHOSContext 返回渲染上下文

image

  1. OH_NativeVSync 原生 VSync 信號驅動幀渲染,VsyncWaiterOHOS 負責等待信號並觸發幀調度,同時支援幀緩存模式的 Dvsync 開關:

image

  1. 最後通過 EmbeddingNodeController(繼承 NodeController)實現,利用 BuilderNodeFrameNode 完成混合渲染,這個我們在之前的 《深入理解 Flutter 的 PlatformView 如何在鴻蒙平台實現混合開發》有聊過。

最後簡單總結的話,類似如下結構:

類別 文件 角色
FlutterAbility embedding/ohos/FlutterAbility.ets UIAbility 子類;應用程序生命週期入口點
FlutterEntry embedding/ohos/FlutterEntry.ets OHOS 頁面級入口點;封裝了 FlutterPage
FlutterView view/FlutterView.ets 擁有 ViewportMetrics,路由觸摸/鍵盤/生命週期事件
FlutterNapi embedding/engine/FlutterNapi.ets 調用 libflutter.so 導出;持有 nativeShellHolderId
TextInputPlugin plugin/editing/TextInputPlugin.ets API 將 Flutter IME 協議橋接到 OHOS inputMethod API
PlatformViewsController plugin/platform/PlatformViewsController.ets 管理嵌入在 Flutter 中的 OHOS 原生視圖
類別 / 文件 角色
PlatformViewOHOSNapi 將 C++ 函數導出為 NAPI 符號;處理 nativeInitnativeAttachnativeDispatchPlatformMessagenativeSetViewportMetrics
PlatformViewOHOS 實現引擎的 PlatformView 接口;創建渲染上下文和表面。
OHOSXComponentAdapter 接收`XComponent Surface 生命週期回調和觸摸事件
OHOSExternalTextureGL / OHOSExternalTextureVulkan GL 和 Vulkan 路徑的外部紋理支援

整體流程如果在鴻蒙視角下流程如下圖所示:

image

我們回顧一下,可以發現,Flutter 在適配鴻蒙的實現上接入十分乾淨,就是拓展了:

  • engine/src/flutter/shell/platform/ohos/:C++ 原生層實現,包含平台適配、渲染後端、NAPI 橋接等
  • engine/src/flutter/shell/platform/ohos/flutter_embedding/:ArkTS 嵌入層實現,提供 Flutter 應用在鴻蒙上的運行時環境

其中 flutter_embedding/ 主要提供 ArkTS 的環境嵌入支援:

  • 入口與生命週期FlutterAbility.etsFlutterEntry.ets 提供兩種宿主模式
  • 引擎管理FlutterEngine.etsFlutterEngineGroup.ets 管理引擎實例與複用
  • 通道系統:各類系統通道(PlatformChannel、TextInputChannel 等)實現
  • 插件架構FlutterPlugin.ets 接口與插件註冊機制

flutter_embedding/ 之外主要提供平台嵌入的底層 C++ 支持,通過 NAPI 與上層 ArkTS 交互

  • 平台視圖PlatformViewOHOS 實現 Flutter 的 PlatformView 接口
  • 渲染後端OHOSSurface 系列類封裝 Vulkan/OpenGL/軟體渲染
  • NAPI 橋接platform_view_ohos_napi.cpp 暴露 native 接口給 ArkTS
  • XComponent 適配ohos_xcomponent_adapter.cpp 處理 XComponent 生命週期

所以從整個鴻蒙的適配實現上,我們就可以很直觀看到 Flutter Embedder 的價值,它可以讓一個全新的系統和平台,用非常乾淨的方式接入 Flutter,並且平台只需要專注於 Embedder 層的實現即可,這也是為什麼 Flutter 在鴻蒙平台跟進速度最快的原因。

最後

從這裡可以看出來,Flutter 的 Embedder 實現才是發揮 Flutter 最大價值的地方,只是它的門檻較高,一般情況只有企業才能發揮它的價值,這也是為什麼 Flutter 會出現在越來越多的產品裡的原因,甚至出現在小米核心應用層、OPPO 負一屏和微信小程序 skyline 的原因,因為它確實很好遷移到不同平台,甚至是特殊平台,你不用 Dart,也需要用它跨平台的渲染管道和 UI 編排能力。

當然,如果社區的 flutter_zero 項目能做起來的話,那 Flutter 的解耦和跨平台能力就可以進一步得到放大,不過這估計是很遙遠之後的事情了。

而現在,在有清晰的結構分層和已有的實現例子上,本身 AI 就可以很快的幫你實現一層 Embedder,這也是 Flutter 在 AI 時代更容易被小眾平台接入為渲染框架的原因。

所以,Flutter 更多的價值體現在於 Embedder 的設計,還有 Impeller 的發布,這些才是 Flutter 的核心資產。


原文出處:https://juejin.cn/post/7610658784424460330


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝22  
628
🥈
我愛JS
💬3  
10
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付