掘力計(jì)劃第 20 期:Flutter 混合開(kāi)發(fā)的混亂之
掘力計(jì)劃第 20 期:Flutter 混合開(kāi)發(fā)的混亂之治
在掘力計(jì)劃系列活動(dòng)第20場(chǎng),《Flutter 開(kāi)發(fā)實(shí)戰(zhàn)詳解》作者,掘金優(yōu)秀作者,Github GSY 系列目負(fù)責(zé)人戀貓的小郭分享了Flutter 混合開(kāi)發(fā)的混亂之治。

Flutter 基于自研的 Skia 引擎實(shí)現(xiàn)了跨平臺(tái)高性能渲染,但其獨(dú)立的渲染層帶來(lái)了與 Android 混合開(kāi)發(fā)的技術(shù)挑戰(zhàn)。經(jīng)過(guò)幾年的演進(jìn),Android 目前提供了多種混合渲染方案,但都無(wú)法完美解決問(wèn)題,且共存于 Flutter API 中,增加了復(fù)雜性。本文將深入解析 Flutter Android 混合開(kāi)發(fā)面臨的困境,以及開(kāi)發(fā)者應(yīng)對(duì)策略。
Flutter 獨(dú)立的渲染機(jī)制

Flutter 能夠跨平臺(tái)高性能渲染的關(guān)鍵在于其自研的 Skia 圖形渲染引擎。Skia 通過(guò)自身的 renderers、GPU 線程等直接與 GPU 層進(jìn)行交互,實(shí)現(xiàn)繪圖功能。這使得 Flutter 的渲染層可以獨(dú)立于 Android 的原生 UI 線程之外。
這種獨(dú)立的渲染機(jī)制給 Flutter 帶來(lái)很大優(yōu)勢(shì),不依賴原生視圖層即可實(shí)現(xiàn)高效的跨平臺(tái)渲染。但是同時(shí)也導(dǎo)致了 Flutter 要與原生視圖進(jìn)行混合開(kāi)發(fā)時(shí)的困難。
如果用一個(gè)簡(jiǎn)單的類比,F(xiàn)lutter 更像是一個(gè)游戲引擎。想要往 Unity 這類游戲引擎中插入原生 Android 視圖,就像往 HTML 中直接嵌入一個(gè) Canvas 元素一樣困難。這需要游戲引擎提供針對(duì)性的接口與機(jī)制,將不同的 UI 系統(tǒng)進(jìn)行「適配」。

針對(duì)這個(gè)問(wèn)題,Android 和 Flutter 社區(qū)也經(jīng)歷了多年的探索,提供了一系列的混合渲染方案。
Android 混合渲染方案演進(jìn)
Android 在支持 Flutter 混合開(kāi)發(fā)時(shí),經(jīng)歷了多種技術(shù)方案的演進(jìn)過(guò)程?,F(xiàn)階段主要存在以下三種混合渲染技術(shù):
VD 模式

VD 全稱 Virtual Display,表示利用虛擬顯示的方式進(jìn)行混合渲染。其關(guān)鍵是采用 VirtualDisplay 將原生視圖渲染到一個(gè)內(nèi)存緩沖區(qū)中,得到相應(yīng)的渲染紋理。
Flutter 通過(guò)特定的 API 調(diào)用,可以獲取這個(gè)渲染紋理,并集成到自身的 Scene 中進(jìn)行統(tǒng)一渲染。
VD 最大的 特點(diǎn)就是渲染的控件其實(shí)不是真實(shí)存在屏幕位置,而是在內(nèi)存,所以容易有觸摸和鍵盤問(wèn)題。
HC 模式

HC 全稱 Hybrid Composition。它的思路是直接將原生視圖通過(guò) Add View 的方式添加到 Flutter 的 View 層次中,進(jìn)行物理層面的視圖混合。

這種直接混合模式可以保存原生視圖的用戶交互,并且可與 Flutter 視圖自由疊加。但是由于需要跨線程同步渲染,可能會(huì)引入一定的性能開(kāi)銷。
TLHC 模式

TLHC 即 Texture Layer Hybrid Composition。這是 Android 團(tuán)隊(duì)後期提出的方案,試圖結(jié)合 VD 和 HC 兩種模式的優(yōu)點(diǎn)。
TLHC 會(huì)通過(guò) hook 原生視圖的 onDraw 方法,將其渲染輸出重定向到內(nèi)存中,再提供給 Flutter 作為紋理。這樣既避免了線程同步,也可以像 HC 那樣自由布局。
但是 TLHC 不支持 SurfaceView 等基于獨(dú)立 Surface 的視圖類型。對(duì)于一些依賴 SurfaceView 的邏輯,如地圖或視頻播放,TLHC 存在兼容性問(wèn)題。
共存的模式帶來(lái)的困境
經(jīng)過(guò)幾年的演進(jìn),F(xiàn)lutter 現(xiàn)在已經(jīng)可以通過(guò)上述三種模式支持 Android 混合開(kāi)發(fā)了。但它們都存在自身的優(yōu)劣勢(shì),無(wú)法解決所有的問(wèn)題場(chǎng)景。

更重要的是,這三種模式現(xiàn)在同時(shí)存在于 Flutter 的 API 中,可以被開(kāi)發(fā)者同時(shí)使用:
// VD模式
initAndroidVew()
// HC模式
initSurfaceAndroidView()
// TLHC模式
initAndroidView()
這其實(shí)帶來(lái)了很大的復(fù)雜性。首先,開(kāi)發(fā)者需要自行理解不同模式的適用場(chǎng)景,進(jìn)行正確的調(diào)用。
其次,隨著 Flutter 版本的演進(jìn),默認(rèn)的模式也在變化。例如在早期只有 VD,到 1.2 提供 HC,3.0 又引入 TLHC。這意味著在版本升級(jí)后,你的混合視圖可能會(huì)在不知情的情況下發(fā)生渲染模式變化,導(dǎo)致問(wèn)題。
再者,TLHC 存在對(duì) SurfaceView 的兼容性問(wèn)題。就算默認(rèn)使用 TLHC,后續(xù)引入 SurfaceView 也可能觸發(fā)問(wèn)題。

除此之外,不同模式的性能開(kāi)銷也存在差異。HC 和 TLHC 的額外渲染消耗需要評(píng)估。模式切換也可能影響渲染性能。
綜上所述,困擾 Flutter Android 混合開(kāi)發(fā)的主要問(wèn)題在于:
存在多種共存的渲染模式,各有特性,選擇復(fù)雜
模式之間兼容性存在,可能引入難以察覺(jué)的問(wèn)題
性能開(kāi)銷和穩(wěn)定性難以保證
這已經(jīng)成為困擾 Flutter 混合渲染的主要困境。
開(kāi)發(fā)者應(yīng)對(duì)策略
面對(duì)復(fù)雜的混合渲染困境,F(xiàn)lutter 開(kāi)發(fā)者也形成了一些應(yīng)對(duì)策略:
優(yōu)先使用 TLHC 模式,能覆蓋更多場(chǎng)景
調(diào)用時(shí)詳細(xì)指定模式,不要依賴默認(rèn)值
注意版本變更帶來(lái)的潛在問(wèn)題
留意是否引入了 SurfaceView 等不兼容場(chǎng)景
評(píng)估不同模式的性能開(kāi)銷區(qū)別
通過(guò)自身封裝控制模式變更范圍
提前測(cè)試不同模式的兼容性
當(dāng)然,這需要開(kāi)發(fā)者對(duì)不同混合渲染模式有足夠的理解,才能做出正確的技術(shù)選型。實(shí)際使用中也需要關(guān)注模式帶來(lái)的兼容性風(fēng)險(xiǎn),建立健壯的自測(cè)方案。
未來(lái) Flutter 混合渲染模式是否還會(huì)繼續(xù)增多也需要持續(xù)跟進(jìn)。理想情況下,如果能夠演進(jìn)出一個(gè)統(tǒng)一的混合解決方案,將大大簡(jiǎn)化 Android 平臺(tái)的混合開(kāi)發(fā)。
總結(jié)
Flutter 基于 Skia 的獨(dú)立渲染機(jī)制,給其在 Android 平臺(tái)的混合開(kāi)發(fā)帶來(lái)了挑戰(zhàn)。經(jīng)過(guò)幾年探索,Android 形成了多種混合渲染方案。但都無(wú)法完美解決問(wèn)題,它們的共存也增加了復(fù)雜性。
開(kāi)發(fā)者需要深入理解不同模式,并有針對(duì)性地進(jìn)行場(chǎng)景選擇和風(fēng)險(xiǎn)評(píng)估。未來(lái)仍需要社區(qū)持續(xù)努力,簡(jiǎn)化這一關(guān)鍵的技術(shù)難題,以進(jìn)一步發(fā)揮 Flutter 的跨平臺(tái)優(yōu)勢(shì)。
關(guān)于掘力計(jì)劃
掘力計(jì)劃由稀土掘金技術(shù)社區(qū)發(fā)起,致力于打造一個(gè)高品質(zhì)的技術(shù)分享和交流的系列品牌。聚集國(guó)內(nèi)外頂尖的技術(shù)專家、開(kāi)發(fā)者和實(shí)踐者,通過(guò)線下沙龍、閉門會(huì)、公開(kāi)課等多種形式分享最前沿的技術(shù)動(dòng)態(tài)。