Flutter Web 支持現已進入穩定版

作者 / Mariam Hasnany, Product Manager, Flutter

我們對 Flutter 的願景是成為一個可移植的 UI 框架,在全平台上構建精美的應用體驗。做為 Flutter 2 發佈內容的一部分,Flutter 的 web 支持已經抵達穩定版里程碑。

Flutter 的首個版本支持 iOS 和 Android,開發者們已經用它在移動應用商店發佈了超過 15 萬個應用。現在,隨着 web 支持的加入,這些應用可以觸達更廣泛的受眾,同時也開闢了在 web 上建立交互體驗的新途徑。

在此次初始版本的 web 支持中,我們主要關注三個應用場景:

  • 漸進式 web 應用 (Progressive web apps, PWA),兼具 web 的高覆蓋面與桌面應用的強大功能。
  • 單頁應用 (Single page apps, SPA),只需一次加載,並與互聯網服務動態互傳數據。
  • 將現有 Flutter 移動應用拓展到 web,在兩個平台共享代碼。

這篇文章介紹了我們迄今為止的工作成果,並分享了幾個案例,意在幫助開發者在自己的應用中活用 Flutter 對 web 的支持。

iRobot Education 使用 Flutter 開發了 iRobot Coding 應用,通過此 web 應用向大眾提供編程學習體驗

Web 之旅

如今的 web 平台比以往任何時候都要豐富多彩,開發者可以使用的工具包括: 硬件加速的 2D 和 3D 圖形離線功能和安裝體驗,以及 對底層操作系統和硬件的訪問 等。在 web 這個底層平台上已經建立起了 種類繁多框架,因此,開發者在創建 web 應用時擁有極大的靈活性。

Flutter 是用 Dart 編寫的,而 Dart 能編譯成 JavaScript,所以我們的下一步自然就是要探討支持 web 平台的可能性。這符合我們的願景,也就是提供一個可移植的框架,方便您在任何能描繪像素的地方構建出精美的 UI。

我們的方法是,建立一個在所有平台上都能使用的一致的工具包 (而不是建立兩個有着各種微妙差異的獨立框架),以確保開發者的代碼運行時不會出現意外。

Flutter 框架由 一系列層結構 組成,其中包含:

  • 框架,用於為 widget、動畫和手勢等常見的習慣用法提供抽象
  • 引擎,使用公開的系統 API 在目標設備上進行渲染

框架本身採用 Dart 編寫,大約 70 萬行 Flutter 框架核心代碼在所有平台上相同: 包括移動端、桌面端和現在的 web 端。對於您的代碼來說也是這樣,我們使用 Dart 開發編譯器 (dartdevc) 或 Dart 部署編譯器 (dart2js) 將您的代碼編譯成 JavaScript,這些 JavaScript 代碼可以託管在服務器上。

由於 Dart 擁有將 Flutter 框架 (以及開發者的應用代碼) 編譯成 JavaScript 的能力,我們對 web 的支持工作就變成了用映射 web 平台 API 的代碼來取代移動應用所使用的底層 C++ 渲染引擎。Flutter 並不會簡單地將 widget 移植為 HTML 里的等價組件,Flutter 的 web 引擎為開發者提供了兩種渲染器: 一個是針對尺寸和兼容性進行優化的 HTML 渲染器,另一個則是使用 WebAssembly 和 WebGL 通過 Skia 繪圖命令向瀏覽器畫布進行渲染的 CanvasKit 渲染器。

我們對 Flutter 的要求是,提供一種針對 web 平台進行開發的新方式,在現有基礎上提供新見解,為所有人提供更棒的 web 體驗。

發佈生產環境可用的穩定版本

自從 web 支持的測試版 在一年前發佈以來,我們已經了解了很多早期採用者的使用情況,並已與部分客戶合作,他們現在已經將自己的 Flutter web 應用投入生產。

在此期間,我們對架構進行了重大改進,增加了一些功能,以便擴展和優化 Flutter 的 web 支持,新增內容主要集中在四個方面: 性能web 專屬功能桌面硬件適配,以及插件

性能

自推出早期版本至今,性能是提升最顯著的。在開發過程中,我們對 web 上各種渲染技術的性能和準確性特徵有了更深入的了解。

我們最早的工作是基於 DOM 的 HTML。在這種渲染模式中,Flutter 的 web 引擎會將每個生成的 Flutter 場景轉換為 HTML、CSS 或 Canvas,並以 HTML 元素樹的形式在頁面上渲染為一幀。雖然 HTML 渲染器能夠最大限度地兼容各種瀏覽器,且其代碼體積較小,但 HTML 渲染器的重繪性能不太適合 Rive (使用 Flutter 構建而成,用於創建動態圖像的協作工具) 這種圖形密集型應用。

Rive 是一款創建自定義動畫的工具,該團隊已使用 web 版 Flutter 重新構建應用,並發佈了測試版

為了提供高效渲染密集圖形所需的保真度,我們開始嘗試使用 CanvasKit,它可使用 WebAssemblyWebGL 通過 Skia 繪製命令在瀏覽器中進行渲染。我們發現 CanvasKit 渲染器的性能、保真度和準確度都更加理想,請看 Flutter 社區中才華橫溢的德國開發者 Felix BlaschkeFlutter Plasma 演示——用 CanvasKit 創造的驚艷特效。

Flutter Plasma 是由 Felix Blaschke 創建的演示,可在 Safari、Firefox、Edge 和 Chrome 上運行

不同的渲染器在不同場景下各有優勢,因此 Flutter 同時支持以下兩種渲染模式:

  • HTML 渲染器: 結合了 HTML 元素、CSS、Canvas 和 SVG。該渲染模式的下載文件體積較小。
  • CanvasKit 渲染器: 渲染效果與 Flutter 移動和桌面端完全一致,性能更好,widget 密度更高,但增加了約 2MB 的下載文件體積。

為了針對每個設備的特性優化您的 Flutter web 應用,渲染模式默認設置為自動。這意味着您的應用將在移動瀏覽器上使用 HTML 渲染器運行,在桌面瀏覽器上使用 CanvasKit 渲染器運行。

您還可以使用 –web-renderer html 或 –web-renderer canvaskit 來明確選擇使用何種渲染器。如需了解詳細信息,請參閱 官方文檔

Web 專屬功能

在瀏覽器中運行的 Flutter 應用給人的感覺應該像 web 應用一樣。所以我們為 Flutter 添加了一些功能,幫助您發揮 web 的優勢。

Web 有很多優勢,尤其是在全球的覆蓋率。將您現有的 Flutter 應用帶到 web 上的原因之一就是接觸應用商店以外的用戶。為了做到這一點,我們添加了 自定義 URL 策略,以確保您的用戶只需點擊 URL,就可以從任何地方訪問您的應用。有了這個功能,您就可以控制地址欄中顯示的 URL,以及您的應用在 web 上的路由。

△ Flutter Plasma 演示的 Showroom 頁面,實際上就是一個基於 Flutter 自定義 URL 策略的 url_strategy 插件示例

當用戶在 web 上導航時,超鏈接也至關重要。url_launcher package 中的一個新的 link widget 使用戶能夠通過深鏈接直達您應用內的錨點或外部網站。您可以在相關的 widget 上使用 link,包括按鈕、內聯文本、圖像,並指定鏈接是在同一個標籤頁還是新標籤頁中打開。

對於任何應用來說,文本渲染都是不可或缺的。開發文本布局系統,是構建 Flutter web 支持所面臨的重大挑戰之一。由於 web 缺乏直接文本布局 API,Flutter 必須通過觸發 layout() 來對 Parapraph 執行各種測量操作。有時,這些測量的代價相當高昂,所以我們添加了 基於 Canvas 的文本測量,此測量方式可同時支持純文本與富文本。現在,Flutter 可以在 web 上高效地完成精細測量,進而完成正確的繪製任務,比如正確地高亮顯示所選文本。

與文本進行交互同樣重要,其重要性不亞於快速準確地渲染文本。通過 SelectableText 和 EditableText widget,您不僅可以選中 Flutter web 應用中的文本,還可以執行複製粘貼操作。此外,表單文本字段現已支持 自動填充,瀏覽器能夠存儲數據以便將來填充使用。

Flutter 2 特別適合實現漸進式 web 應用 (PWA)。我們建議開發者使用 PWA,通過 Chrome 的 Project Fugu,以安全和可信的方式,彌合移動端和 web 端應用之間的差異。

△ 發票管理應用 Invoice Ninja 推出的 PWA 應用與他們現有的 Flutter 移動應用使用相同的代碼庫

在創建 Flutter Web 應用時,我們會提供 PWA web 清單文件,以及用來設置 service worker (工作線程) 的代碼。清單文件提供了關於應用應該如何運行的元數據,包括圖標和應用標題等信息。Service workers 可以實現資源的緩存和應用的離線運行。當您在瀏覽器中以 PWA 的形式運行 Flutter 應用時,您可以將其作為移動或桌面應用安裝到您的設備上。

適配各類桌面設備

儘管瀏覽器的形態大小各異,我們都希望提供美好的 Flutter web 體驗。由於 Flutter 最初是為移動應用設計而成,因此 Flutter web 應用已經對移動瀏覽器的手勢和滾動物理效果提供了很好的支持。但桌面瀏覽器 UI 的呈現和使用有所不同,所以我們對 Flutter 進行了相應的更新。

比如,用戶希望應用在桌面瀏覽器中運行時能夠顯示滾動條,以便通過鼠標或鍵盤進行控制。我們為桌面設備添加了 可自定義的交互式滾動條,這意味着我們可為滾動條使用 主題,顯示滾動條軌道,而且還可以拖動滑塊。我們還擴展了 PrimaryScrollController,便於用戶 使用鍵盤快捷鍵進行滾動,也省去了您使用自定義滾動視圖的工作。

Spica TechnologiesZurich Insurance 構建的物業管理解決方案,這是用 Flutter web 為商務和桌面設備用戶構建應用的傑出示例

此外,由於鼠標指針能進行互動的內容密度大於觸摸設備,我們提升了 默認內容密度。我們還在框架中添加了支持各種平台的 系統鼠標光標 合集。

最後,為讓 Flutter web 支持所有用戶,我們還擴展了 Flutter 的 web 語義功能來支持 Windows、macOS 和 chromeOS 系統上的無障礙功能。為了在 web 上實現無障礙體驗,我們在 RenderObject DOM 樹之外平行生成了一個類似的 DOM 樹,叫 SemanticsNode 樹。SemanticsNode 樹可將標記、操作、標籤和其他語義屬性轉換成 ARIA 屬性。現在,您可以通過 NarratorVoiceOverTalkBackChromeVox 屏幕閱讀器來使用 Flutter web 應用。

Flutter web 對插件的支持

最後,我們為那些最常用的插件帶來了 web 支持,使您能夠將自己的 Flutter 應用帶到 web 平台。藉助 Flutter 插件,您的代碼可與所運行平台的原生開發庫進行互操作。在 web 上運行 Flutter 應用時,您可以通過插件訪問現有的 JavaScript 庫。

自測試版發佈以來,我們在社區的幫助下為以下插件添加了 web 支持:

展望未來

幾年前,我們還沒辦法在 web 上以可接受的質量和性能提供 Flutter。然而,web 新技術的出現和平台的不斷進步,使我們得以盡情釋放底層設備的潛力。在支持 web 之後,Flutter 得以涵蓋互聯網上的每一台設備,讓用戶在所有現代瀏覽器和設備上都能獲得一致的體驗。

這個版本的相當一部分內容來自早期 web 用戶的反饋信息和社區提交的 issue,這裡我們要再次感謝大家的貢獻!今後,我們的首要目標是快速處理大家的反饋,並及時解決 issue,以便大家專註於在所有目標平台上發佈高質量的 Flutter 應用。

Moi Mobiili 是一家現代移動虛擬網絡運營商,最近使用 Flutter 推出了他們的 web 應用

性能的提升永無止境。我們的目標是減少代碼體積,提高幀率表現 (fps)。如今,每個 Flutter web 應用都只會下載它必需的引擎代碼。我們正在研究緩存部分邏輯的可能性,以減少啟動時間和下載文件體積。我們最近在 Flutter Gallery 演示應用中嘗試使用延遲庫來減少代碼體積,相信很快就能同大家分享我們的進展。

在未來幾個月內,我們還準備繼續完善下列領域:

  • 雖然 CanvasKit 很穩定,但還有一些邊界用例存在問題,比如特殊字符的 字體回退,以及對 跨域資源共享 (CORS) 圖像的相應支持等。
  • PWA 目前 只緩存了資源的一個子集,完全的離線支持仍然需要 額外的手動步驟,才能正常適配 CanvasKit。
  • 文本渲染和功能,比如對樣式設置較為複雜的文本的選取,仍是我們要繼續努力解決的功能之一。
  • 我們也會繼續努力改善插件生態系統,讓 Google 發佈的 package 在移動端和 web 端更加統一。

Simplebet 通過 Flutter 的 web 支持,在 Fanduel 現有的移動應用套件中構建了高度互動的嵌入式 NFL 和 NBA 投注體驗

即刻開始使用 Flutter web

藉助 Dart 的可移植性、Web 平台的強大功能,以及 Flutter 框架的靈活性,您現在可以用同一套代碼庫,構建用於 iOS、Android 以及瀏覽器的應用。

如果您已經開發了 Flutter web 應用,現在就可以在 穩定渠道 中進行構建。如果您剛開始學習構建 Flutter web 應用,請移步官方文檔訪問我們的 入門 codelab 課程,以及 Flutter Engage 上的 web 演講。構建 web 應用時,如果您發現了任何問題,請隨時 前往 GitHub 提交給我們

我們非常期待看到您使用 Flutter web 所構建的精彩應用!

Tags: