背景
隨著移動端從誕生到遍地開發(fā)再到平臺化的收斂,為了不斷滿足企業(yè)對于開發(fā)效率及跨平臺的一致性的追求,各種跨平臺方案層出不窮。對于我們做產(chǎn)品設(shè)計和開發(fā),開發(fā)效率和使用體驗可以說是至關(guān)重要的兩個因素。如果你身處大前端,你就不得不擁抱跨端,這是一個不以人意志為轉(zhuǎn)移的趨勢。從本質(zhì)上來講,跨平臺開發(fā)是為了增加業(yè)務(wù)代碼的復(fù)用率,減少因為要滿足多個平臺的適配開發(fā)而帶來的開發(fā)和維護成本,從而有效降低開發(fā)成本。
方案演進
無論大大小小的跨平臺方案,按照其核心的設(shè)計思想,可以劃分了三個階段
- Web 容器
基于設(shè)備系統(tǒng)原生的瀏覽器組件來實現(xiàn)頁面及業(yè)務(wù)功能。代表方案有:cordova等 - 泛Web容器
采用web標(biāo)準(zhǔn)進行開發(fā),在運行時由原生系統(tǒng)負(fù)責(zé)渲染繪制。代表方案有:RN、Weex等 - 自渲染引擎
自帶渲染引擎,客戶端僅需要提供畫布便可以實現(xiàn)業(yè)務(wù)功能到UI的多端一致的渲染體驗。代表方案:Flutter
下面我們逐個分析這三個階段不同的設(shè)計思想與各自的優(yōu)勢
Web容器
Web 容器的方案,是最簡單也最易操作的方案,主要采用原生系統(tǒng)內(nèi)嵌的瀏覽器控件(Android的WebView,iOS的WKWebView)的方式渲染H5頁面。客戶端與HT定義好交互的協(xié)議,將一些原生系統(tǒng)能力暴露給H5通過js來調(diào)起,也就是大家說的 JSBridge。
web容器的交互設(shè)計可以通過下圖來直觀提現(xiàn)
這種方案最終的渲染方還是瀏覽器,一個H5頁面呈現(xiàn)出來是要經(jīng)過較為復(fù)雜的過程,我們可以陳列下最基礎(chǔ)的加載過程,就可以知道這個過程的復(fù)雜性。
- 瀏覽器控件加載 HTML5 頁面的 HTML 主文檔。
- 加載過程中遇到外部 CSS 文件,瀏覽器另外發(fā)出一個請求,來獲取 CSS 文件。
- 遇到圖片資源,瀏覽器也會另外發(fā)出一個請求,來獲取圖片資源。這是異步請求,并不會影響 HTML 文檔的加載。
- 加載過程中遇到 JavaScript 文件,由于 JavaScript 代碼可能會修改 DOM 樹,因此 HTML 文檔會掛起渲染(加載解析渲染同步)的線程,直到 JavaScript 文件加載解析并執(zhí)行完畢,才可以恢復(fù) HTML 文檔的渲染線程。
- JavaScript 代碼中有用到 CSS 文件中的屬性樣式,于是阻塞,等待 CSS 加載完畢才能恢復(fù)執(zhí)行。
從這個過程我們可以看出,一個完成的H5頁面的呈現(xiàn)要經(jīng)過瀏覽器控件的加載、解析和渲染三大過程,性能消耗和呈現(xiàn)效率相比原生頁面都有很大的負(fù)面增加。雖然Web容器方案開發(fā)體驗友好,跨平臺兼容性強等優(yōu)勢,但需要承載大量的與Web指定的協(xié)議標(biāo)準(zhǔn),會導(dǎo)致容器過于笨重,而且較難實現(xiàn)復(fù)雜交互和呈現(xiàn)較好的用戶體驗
泛Web容器
泛Web容器的方案優(yōu)化了Web容器方案的瀏覽器加載、解析和渲染這三大過程,把影響它們獨立運行的 Web 標(biāo)準(zhǔn)進行了裁剪,以相對簡單的方式支持了構(gòu)建移動端頁面必要的 Web 標(biāo)準(zhǔn)(如 Flexbox 等),也保證了便捷的前端開發(fā)體驗;同時,這個時代的解決方案基本上完全放棄了瀏覽器控件渲染,而是采用原生自帶的 UI 組件實現(xiàn)代替了核心的渲染引擎,僅保持必要的基本控件渲染能力,從而使得渲染過程更加簡化,也保證了良好的渲染性能。也就是說,在泛 Web 容器時代,我們?nèi)匀徊捎们岸擞押玫?JavaScript 進行開發(fā),整體加載、渲染機制大大簡化,并且由原生接管繪制,即將原生系統(tǒng)作為渲染的后端,為依托于 JavaScript 虛擬機的 JavaScript 代碼提供所需要的 UI 控件的實體。這,也是現(xiàn)在絕大部分跨平臺框架的思路。RN和Weex就是采用了這種設(shè)計方案。
為了追求更好的性能體驗,進一步位置方案的簡單可擴展性,一些公司已經(jīng)放棄Web標(biāo)準(zhǔn)。放棄JS的動態(tài)執(zhí)行能力,而自研一套原生的DSL解析器來實現(xiàn)跨端方案,例如天貓、美團、滴滴等。
自渲染引擎
泛 Web 容器方案使用原生控件承載界面渲染,解決了不少性能問題,但同時也帶來了新的問題。拋開框架本身需要處理大量平臺相關(guān)的邏輯外,隨著系統(tǒng)版本變化和 API 的變化,我們還需要處理不同平臺的原生控件渲染能力差異,修復(fù)各類奇奇怪怪的 Bug。始終需要 Follow Native 的思維方式,而Flutter 則使用了一種全新的思路,即從頭到尾重寫一套跨平臺的 UI 框架,包括渲染邏輯,甚至是開發(fā)語言。
- 渲染引擎依靠跨平臺的 Skia 圖形庫來實現(xiàn),Skia 引擎會將使用 Dart 構(gòu)建的抽象的視圖結(jié)構(gòu)數(shù)據(jù)加工成 GPU 數(shù)據(jù),交由 OpenGL 最終提供給 GPU 渲染,至此完成渲染閉環(huán),因此可以在最大程度上保證一款應(yīng)用在不同平臺、不同設(shè)備上的體驗一致性。
-
開發(fā)語言選用的是同時支持 JIT(Just-in-Time,即時編譯)和 AOT(Ahead-of-Time,預(yù)編譯)的 Dart,不僅保證了開發(fā)效率,更提升了執(zhí)行效率(比使用 JavaScript 開發(fā)的泛 Web 容器方案要高得多)。
自渲染.png
通過這樣的思路,F(xiàn)lutter 可以盡可能地減少不同平臺之間的差異, 同時保持和原生開發(fā)一樣的高性能。Flutter 成了三類跨平臺移動開發(fā)方案中最靈活的那個,目前也是熱度相對較高的跨平臺方案。
我們的選擇
對比三種方案最具代表的框架,我們可以對比他們不同的優(yōu)劣
我們在做技術(shù)選型時,要從團隊規(guī)模、開發(fā)效率、技術(shù)棧、性能表現(xiàn)、維護成本和社區(qū)生態(tài)來進行綜合考慮。比如,是否必須支持動態(tài)化?是只解決 Android、iOS 的跨端問題,還是要包括 Web?對性能要求如何?對多端體驗的絕對一致性和維護成本是否有強訴求?社區(qū)是否足夠活躍,能夠交流更多的疑難問題和解決方案,這些都是我們要考慮的。因為一旦選型后,業(yè)務(wù)的推動過程中,這些問題點最終都是要自己消化掉的。判斷一個技術(shù)是否能成為未來大前端主流技術(shù)發(fā)展的趨勢,主要看這個技術(shù)是否能減少對底層宿主環(huán)境的依賴,隔離各終端系統(tǒng)差異,能否從原理和運行機制及生態(tài)有領(lǐng)先同類產(chǎn)品的表現(xiàn),向開發(fā)者提供統(tǒng)一而標(biāo)準(zhǔn)化的能力。