成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

打破重重阻礙,Flutter 和 Web 生態如何對接?

開發 架構
Flutter 設計之初是不考慮 Web 生態的,原因很簡單:兩種技術設計理念不同,強行融合很可能讓彼此都喪失了優勢。但是業界又有很多團隊在做這種嘗試,說明需求是存在的。今天,阿里無線開發專家門柳就來手把手教如何實現 Flutter 和 Web 生態的對接?

 [[316056]]

阿里妹導讀:Flutter 設計之初是不考慮 Web 生態的,原因很簡單:兩種技術設計理念不同,強行融合很可能讓彼此都喪失了優勢。但是業界又有很多團隊在做這種嘗試,說明需求是存在的。今天,阿里無線開發專家門柳就來手把手教如何實現 Flutter 和 Web 生態的對接?

先說結論:

不要對接!不要對接!不要對接!

開個玩笑,以上僅代表個人觀點,大家也知道這種“三體式警告”根本沒有用的,我自己也研究如何對接,說不定做完后就覺得“真香”了。

為什么要對接?

首先討論一下為什么要把 Flutter 對接到 Web 生態。

Flutter 現在是一個炙手可熱的跨平臺技術,能夠一套代碼運行在 Android、iOS、PC、IoT 以及瀏覽器上,被認為是下一代跨平臺技術。相比于 Weex 和 React Native 可以很好地解決多平臺一致性問題,原生渲染性能相近,上層沒有 JS 那么厚的封裝層次,整體性能會略好一些。

但是大部分興沖沖去學 Flutter 的人疑惑的第一個問題就是:為什么 Flutter 要用 Dart?一個全新的語言意味著新的學習成本,難道 JS 不香嗎?JS 不香不是還有 TypeScript 嗎!事實上 Flutter 拋棄的豈止是 JS 這門語言,也拋棄了 HTML 和 CSS,設計了一套解耦得更好的 Widget 體系,Flutter 拋棄的是整個 Web,致力于打造一個新的生態,但是這個生態無法復用 Web 生態的代碼和解決方案。尤其是之前所有跨平臺方案 Hybrid、React Native、Weex 都是對接 Web 生態的,這讓 Flutter 顯得有些格格不入,也讓大部分前端開發者望而卻步。

下面是我整理出來的,前端開發者使用 Flutter 的各方面成本:

 

 

 

 

因為 Flutter 的開發模式和前端框架比較像(可以說就是抄的 React),所以框架的學習成本并不高,稍微高一些的是 Dart 語言的學習成本,另外還要學習如何用 Widget 組裝 UI,雖然很多布局 Widget 設計得和 CSS 很像,靈活度還是差了很多。要想在真實項目中用起來,還要改造整個工具鏈,以“Native First”的視角做開發,開發 Flutter 和開發原生應用的鏈路是比較像的,和開發前端頁面有較大差異。最高的還是生態成本,前端生態的積累無論是代碼還是技術方案都很難復用,這是最痛的一點,生態也是 Flutter 最弱的一環。

無論是為了先進的技術理念還是出于商業私心,先不管 Flutter 為什么拋棄 Web 生態,現實問題是最大的 UI 開發者群體是前端,最豐富的生態是 Web 生態,我覺得 Web 技術也是開發 UI 最高效的方式。如果能在上層使用 Web 技術棧開發,在底層使用 Flutter 實現跨平臺渲染,不是可以很好的兼顧開發效率、性能和跨平臺一致性嗎?還能復用 Web 技術棧大量的技術積累。

可能這些理由也不夠充分,暫且先照著這個假設繼續分析,最后再重新討論到底該不該對接。

關于 Flutter 和 Web 生態的對接涉及兩個方面:

  • 從 Web 到 Flutter。就是使用 Web 技術棧來開發,然后對接到 Flutter 上實現跨平臺渲染。對 Web 來說是解決性能和跨平臺一致性問題,對 Flutter 來說是解決生態復用問題。
  • 從 Flutter 到 Web。就是官方已經實現的 Web support for Flutter,把已經用 Dart 開發好的 App 編譯成 HTML/JS/CSS 然后運行在瀏覽器上,可以用于降級和外投場景。

如何實現“從 Web 到 Flutter”?

首先分析一下 Flutter 的架構圖,看看可以從哪里下手。

 

 

 

 

Flutter 可以分為 Framework 和 Engine 兩部分,Engine 部分比較底層也比較穩定了,最好不要動,需要改的是用 Dart 實現的 Framework。要想對接 Web 生態的話,JS 引擎肯定是要引入的,至于是否保留 Dart VM 有待討論。圖中最上面 Material 和 Cupertino 兩個 UI 庫前端是不需要的,前端有自己的。關鍵是 Widget 這部分,是替換成 HTML/CSS 的方式寫 UI,還是繼續保留 Widget 但是把語言換成 JS,不同方案給出的解法也不一樣。

有不少方案可以實現對接,業界有挺多嘗試的,我總結了下面三種方式:

  • TS 魔改:用 JS 引擎替換掉 Dart VM,用 JS/TS 重新實現 Flutter Framework(或者直接 dart2js 編譯過來)。
  • JS 對接:引入 JS 引擎同時保留 Dart VM,用前端框架對接 Flutter Framework。
  • C++ 魔改:用 JS 引擎替換掉 Dart VM,用 C++ 重新實現 Flutter Framework。

TS 魔改

TS 魔改就是完全拋棄掉 Dart VM,用 TypeScript 重新實現一遍用 Dart 寫的 Flutter Framework。

為啥是 TS 而不是 JS?這不是因為 TS 是個大熱門嘛,而且向下兼容 JS,現在幾乎所有時髦的框架都要用 TS 重寫了。

這種方案的出發點是“如果能把 Flutter 的 Dart 換成 JS 就好了”,最容易想到的路就是把 Dart 翻譯成 TS,或者直接用 dart2js 把代碼編譯成 js,但是編譯出來的代碼包含很多 dart:ui 之類的庫的封裝,生成的包也挺大的,也比較難定制需要導出的接口,不如干脆用 TS 重寫一遍,工具鏈更熟悉一些,還可以加一些定制。

理論上講翻譯之后 Flutter 絕大部分功能都依然支持,可以復用各種 npm 包,還可以動態化,但是喪失了 AOT 能力,JS 語言的執行性能應該是不如 Dart 的。而且所有節點的布局運算都發生在 JS,底層只需要提供基礎的圖形能力就好了,就好像是基于 Canvas API 寫了一套 UI 框架,性能未必有現存前端框架的性能高。

此外最大的問題是如何與官方 Flutter 保持一致,假如現在是從 v1.13 版本翻譯過來的,以后官方升級到了 v1.15 要不要同步更新?這個過程沒啥技術含量,而且需要持續投入,做起來比較惡心。

另外還需要考慮上層是用 Widget 的方式寫 UI,還是用前端熟悉的 HTML+CSS。如果依然用 Widget 的話,那大部分前端組件還是用不了的,UI 還是得重寫一遍。反正要重寫的話,成本也沒降下來,那就用 Dart 重寫唄…… 直接用官方原版 Flutter 也避免每次更新都要翻譯一遍 Dart 代碼。所以既然選擇了對接前端生態,那就要對接 CSS,不然就沒有足夠的價值。然而 CSS 和 Widget 的對接也是很繁瑣的過程,而且存在完備性問題。

JS 對接

翻譯代碼的方式不夠優雅,那就保留 Dart,把 JS/CSS 對接到 Widget 上面不就好了?

當然可以,這種方式是僅把 Flutter 當做了底層的渲染引擎,上層保持前端框架的寫法,僅把渲染部分對接到 Flutter。現存的很多前端框架都把底層渲染能力做了抽象,可以對接到不同渲染引擎上,如 Vue/Rax 同時支持瀏覽器和 Weex,用同樣的方式,可以再支持一個 Flutter。

這種方式對前端框架的兼容性比較好,但是鏈路太長了,業務代碼調用前端框架接口做渲染,一頓操作之后發出了渲染指令,這個渲染指令要基于通信的方式傳給 Flutter Framework,這中間涉及一次 JS 到 C++ 再到 Dart 的跨語言轉換,然后再接收到渲染指令之后還要轉成相應的 Widget 樹,從 CSS 到 Widget 的轉換依然很繁瑣。而且 Widget 本身是可以帶有狀態的,本身就是響應式更新的,在更新時會重新生成 widget 并 diff,如果在前端更新 UI 的話,前端框架在 js 里 diff 一次 vdom,傳到 Flutter 之后又 diff 一次 widget。

如果要繞過 Widget 直接對接圖中的 Rendering 這一層,可以繞過 widget diff 但是得改 Flutter Framework 的渲染鏈路,既然要改 Flutter Framework 那為什么不直接用 TS 魔改呢,還繞過了 JS 到 Dart 的通信,又回到了第一種方案。

總結來說,這個方案的優點是:實現簡單、能最大化保留前端開發體驗,缺點是:渲染鏈路長、通信成本高、響應式邏輯沖突、CSS 轉 Widget 不完備等。

C++ 魔改

想要干掉 Dart VM,就需要用其他語言重新實現用 Dart 開發的 Framework,用 JS/TS 可以,用 C++ 當然可以,最硬核的方式就是用 C++ 重新實現 Flutter 的 Framework,然后接入 JS 引擎,通過 binding 把 C++ 接口透出到 JS 環境,上層應用還是用 JS 做開發。

把 Framework 層下沉到 C++ 之后,不僅會有更好的性能,也能支持更多語言。原本 Flutter Framework 是在 Dart VM 之上的,必須依賴 Dart VM 才能運行,所以對 Dart 有強依賴;用 C++ 重新實現之后,JS 引擎是在 C++ 版 Framework 之上的,框架本身并不依賴 JS 引擎,還可以對接其他各種語言,如對接了 JVM 之后可以支持 Java 和 Kotlin,對接回 Dart VM 可以繼續支持 Dart。

這個方案可以增強性能,也能保持和 Flutter 的一致性,但是改造成本和維護成本都相當高。C++ 的開發效率肯定不如 Dart,當 Flutter 快速迭代之后如何跟進是很大的問題,如果跟進不及時或者實現不一致那很可能就分化了。從 CSS 到 Widget 的轉換也是不得不面對的問題。

幾種方案對比

把上面幾種方案畫在同一張圖里是這個樣子的:

 

 

 

 

圖中實線部分表示了跨語言的通信,太過頻繁會影響性能,虛線部分表示了其他對接可能性。

從下到上,Flutter Engine 是不需要動的,這一層是跨平臺的關鍵。Framework 則有三種語言版本,JS/TS、Dart、C++,性能是 C++ 版本最好,成本是 Dart 版本最低。然后還需要向上處理 HTML/CSS 和 Widget 的問題,可以直接對接一個前端框架,也可以直接在 C++ 層實現(不然需要透出的 binding 接口就太多了,用通信的方式也太過頻繁了)。

如何實現“從 Flutter 到 Web”?

這個功能官方已經實現了,可以把使用 Dart 開發的 App 編譯成 Web App 運行在瀏覽器上,官方文檔以介紹用法和 API 為主,我這里簡單分析一下內部具體的實現方案。

實現原理

結合 Flutter 的架構圖來看,要實現 Web 到 Flutter 需要改造的是上層 Framework,要實現 Flutter 到 Web 需要改造的則是底層 Engine。

 

 

 

 

Framework 對 Engine 的核心依賴是 dart:ui,這是庫是在 Engine 里實現的,抽象出了繪制 UI 圖層的接口,底層對接 skia 的實現,向上透出 Dart 語言的接口。這樣來看,對接方式就比較簡單了:

  • 使用 dart2js 把 Framework 編譯成 JS 代碼。
  • 基于瀏覽器的 API 重新實現 dart:ui,即 dart:web_ui。

把 Dart 編譯成 JS 沒什么問題,性能可能會有一點影響,功能都是可以完全保留的,關鍵是 dart:web_ui 的實現。在原生 Engine 中,dart:ui 依賴 skia 透出的 SkCanvas 實現繪制,這是一套很底層的圖形接口,只定義了畫線、畫多邊形、貼圖之類的底層能力,用瀏覽器接口實現這一套接口還是很有挑戰的。上圖可以看到 Web 版 Engine 是基于 DOM 和 Canvas 實現的,底層定義了 DomCanvas 和 BitmapCanvas 兩種圖形接口,會把傳來的 layer tree 渲染成瀏覽器的 Element tree,但是節點上僅包含了 position, transform, opacity 之類的樣式,只用到 CSS 很小的一個子集,一些更復雜的繪制直接用2D <canvas> 實現。

存在的問題

我編譯了一個還算復雜的 demo 試了一下,性能很不理想,滑動不流暢,有時候圖片還會閃動。生成出來的 js 代碼有 1.1MB (minify 之后,未 gzip),節點層次也比較深,我評估這個頁面用前端寫不會超過 300KB,節點數可以少一半以上。

另外再看一下 Flutter 倉庫的 issue,過濾出 platfrom-web 相關的,可以看到大量:文字編輯失效、找不到光標、ListView 在 ios 上不可滾動、checkbox/button 行為不正常、安卓滾動卡頓圖片閃爍、字體失效、某些機型視頻無法播放、文字選中后無法復制、無法調試…… 感覺 flutter for web 已經陷入泥潭,讓人回想起前端當年處理各種瀏覽器兼容性的噩夢。

這些性能和兼容性問題,核心原因是瀏覽器未暴露足夠的底層能力,以及瀏覽器處理手勢、用戶輸入和方式和 Flutter 差異巨大。

實現 Flutter Engine 需要的是底層的圖形接口和系統能力,雖然 <canvas> 提供了相似的圖形接口,如果全部用 canvas 實現的話很難處理可訪問性、文本選擇、手勢、表單等問題,也會存在很多兼容性問題。所以真實方案里用的是 Canvas + DOM 混合的方式,封裝層次太高了,渲染鏈路太長。就好像 Flutter Framework 里進行了一頓猛如虎的操作之后,節點生成好了、布局算好了、繪制屬性也處理好了,就差一個畫布畫出來了,然后交到瀏覽器手里,又生成一遍 Element,再算一遍布局,在處理一遍繪制,最終才交給了底層的圖形庫畫出來。

再比如長頁面的滾動,瀏覽器里只要一條 CSS (overflow:scroll) 就可以讓元素可滾動,手勢的監聽以及頁面的滾動以及滾動動畫都是瀏覽器原生實現的,不需要與 JS 交互,甚至不需要重新 layout 和 paint,只需要 compositing。如上圖所示,在 Flutter 中 Animation 和 Gesture 是用 Dart 實現的,編譯過來就是 JS 實現的,瀏覽器本身并不知道這個元素是否可滾,只是不斷派發 touchmove 事件,JS 根據事件屬性計算節點偏移,然后運算動畫,然后把 transform 或者新的 position 作用到節點上,然后瀏覽器再來一遍完整的渲染流程……

優化方案

性能和兼容性的問題還是要解決的,短期內先把 issue 解掉,長線的優化方案,官方有兩種嘗試:

使用 CSS Painting API 做繪制。

  • 這是還處于提案狀態的新標準,可以用 JS 實現一些繪制功能,自定義 CSS 屬性。
  • 目前還未實現,需要等瀏覽器先把 CSS Houdini 支持好。

使用 WebAssembly 版本的 Skia 做繪制。https://skia.org/user/modules/canvaskit

  • 這樣可以發揮 wasm 的性能優勢,并且保持 skia 功能的一致。但是目前 wasm 在瀏覽器環境里未必有性能優勢,這里不展開討論了。
  • 已經部分實現,參考這里的配置啟用功能: https://github.com/flutter/flutter/issues/41062#issuecomment-533952994

這兩個方案都是想更多的利用到瀏覽器的底層能力,只有瀏覽器暴露了更多底層能力,才能更好的實現 Flutter 的 Web Engine。不過這個要等挺久的時間,我們也參與不了,現階段想要使用 flutter for web,還是得保持現有架構,一起參與進去把 issue 解決掉,優先保障功能,其次優化性能。

一種適應性更好的架構

如果理想化一點,能不能從架構角度讓 Flutter 和 Web 生態融合的更好一些呢?

回顧文章最開始的官方架構圖,上面是 Framework(Dart),下面是 Engine(C++),切分在 Foundation 這一層,雙方之間的交互是幾何圖形信息。如果還保持這個架構,把切分層次劃分的更靠上一些,如下圖所示,劃分在 Widgets 和 Rendering 這一層,理論上講對 Flutter 的開發者來說是無感知的,因為上層的開發語言和 Widget 接口都是不變的。

 

 

 

 

切分在這一層,Framework 和 Engine 之間的交互就不再是幾何圖形而是節點信息,Widget 的組合、setState 響應式更新、Widget diff 都還在 Dart 中,展開后的 RenderObject 的布局、繪制、裁剪、動畫全都在 C++ 中,不僅有更好的性能,還可以與 Engine 有更好的結合。

或者說,還原本保留 Engine 的設計,把下沉的這部分邏輯上劃分成 Renderer,就有了如下三層的結構:

 

 

 

 

這樣劃分出來的每一層都有明確的定位:

  • Framework: 開發框架。為開發者提供可編程 API,實現響應式的開發模式,提供細粒度 Widget 供開發者自由封裝和組合。
  • Renderer: 渲染引擎。專門實現布局、繪制、動畫、手勢的的處理,這部分功能相對獨立,是可以與開發框架解耦的,也不必與特定語言綁定。
  • Engine: 圖形引擎。實現跨平臺一致的圖形接口,合成輸入的層并繪制到屏幕上,處理好平臺力的接入和適配。

這樣切分除了有性能優勢以外,也使得渲染引擎擺脫了對 Dart 的依賴,能夠支持多種語言,也能支持多種開發模式。對接到 Dart VM 就可以用 Dart 寫代碼,對接到 JS 引擎就可以用 JS 寫代碼,對接到 JVM 還可以寫 Java,但是無論怎么寫,底層的渲染能力是一樣的,一套統一的布局算法,動畫和手勢的處理行為也是一致的。

在這樣的架構下,對接 Web 生態就更容易了。Dart 和 Widget 是前端不想要的,希望能換成 JS 和 CSS,但是又想要底層的跨平臺一致渲染引擎,那從 Renderer 層開始對接就好了,繞過了所有不想要的,也保留了所有想要的。

 

 

 

 

要實現 Flutter for Web 也更簡單了一些。在 Engine 層做對接,一直苦于瀏覽器透出的底層能力不夠,如果是在 Renderer 之上做對接就更容易一些,基于 JS/CSS/DOM/Canvas 的能力封裝出一套 Rendering 接口,供 Widget 調用就好了,這樣可以使渲染鏈路更短一些,但是依然要處理 Widget 和 DOM/CSS 之間的兼容性問題。

再討論一遍:為什么要對接?

技術上已經分析完了,要想搞定 Flutter 生態和 Web 生態的對接,需要投入很大的成本,所以真正決定做之前,要先討論清楚為什么要做對接?到底要不要做對接?

首先 Google 官方對 Flutter 的定位就是個問題。Flutter 設計之初就是不考慮 Web 生態的,甚至在刻意回避,倡導的是更貼近原生的開發方式。我之所以在開頭說不要對接,原因也很簡單:兩種技術設計理念不同,不是朝著一個方向發展的,生態不通,技術方案不通,強行融合很可能讓彼此都喪失了優勢。但是業界又有很多團隊在做這種嘗試,說明需求是存在的,如果 Google 抵制這個方向,那就不好做了。不過現在官方已經支持了 Flutter for Web,已經向 Web 生態邁了一步,未來是否進一步與 Web 融合,也是有可能的。

另外就是跨平臺技術本身的問題,瀏覽器發展了二三十年,已經是個很強大的跨平臺產品了,幾乎是 Web 的代名詞了,這一點無人能敵。但是也臃腫不堪,有大量歷史包袱,性能和體驗不夠好,和 Native 的結合度差,尤其在移動和 IoT 平臺。雖然硬件性能在不斷提升,但這是所有軟件共享的,瀏覽器的性能和體驗總會比 Native 差一些,差的這一些很可能就是新業務和新場景的發揮空間。觀察一下近幾年新誕生的業務場景,很多都是利用到了 Native 新提供的能力才火爆起來的,如 AI/AR/視頻/直播 等,有因為新的 Web API 而孵化生出來的商業模式嗎?

關于這個話題,希望大家能發表一下自己的看法。

責任編輯:武曉燕 來源: 阿里技術
相關推薦

2009-09-15 08:25:01

Windows 7系統升級

2023-03-02 20:21:17

2023-09-06 08:14:34

性能優化模式

2017-09-25 12:31:51

2015-05-21 10:15:07

2015-11-06 15:14:50

大廠

2022-09-08 15:27:28

元宇宙數字化轉型通信技術

2024-02-20 01:53:01

ReactFlutter開發

2023-05-05 07:03:12

2013-03-05 09:47:11

2020-11-30 14:24:53

攜號轉網轉網率阻礙

2024-12-26 08:02:36

API?Navigator嵌套路由

2022-04-13 13:45:41

區塊鏈Web3加密貨幣

2011-07-28 20:32:51

2017-07-24 13:44:10

戴爾服務器架構

2020-02-14 19:13:35

SprintT-Mobile通信

2011-07-29 10:51:26

2014-02-11 13:22:39

2019-12-18 14:39:44

云計算云安全數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区精品视频 | 在线免费中文字幕 | 欧美精品一区二区三区在线 | 亚洲一区中文字幕 | 天天在线操 | 日韩福利电影 | 久久三级av | aaa天堂| 久久精品一区 | a在线视频 | 成人在线视频免费观看 | 色网在线看 | 日本精品裸体写真集在线观看 | 毛片免费观看视频 | 欧美成人第一页 | 国产成人精品久久 | 99久久免费观看 | 天堂综合| 成人福利在线 | 国产成人免费 | 亚洲日本中文字幕在线 | 久久亚洲一区二区三区四区 | 欧美日韩亚洲视频 | 久久91精品国产一区二区 | 久久伊人久久 | 国产精品一区久久久 | 日韩欧美在线视频 | 在线观看中文字幕 | 国产精品久久久久影院色老大 | 毛片毛片毛片毛片毛片 | 国产在线观看 | 黄色一级视频 | 日韩一二三区视频 | 国产精品久久久久久久久久三级 | 久久精品国产一区老色匹 | 亚洲精品电影 | 日本淫视频| 亚洲每日更新 | 国产亚洲欧美日韩精品一区二区三区 | 超碰男人天堂 | 精品网站999www |