背景
隨著移動端從誕生到遍地開發(fā)再到平臺化的收斂,為了不斷滿足企業(yè)對于開發(fā)效率及跨平臺的一致性的追求丈甸,各種跨平臺方案層出不窮糯俗。對于我們做產品設計和開發(fā),開發(fā)效率和使用體驗可以說是至關重要的兩個因素睦擂。如果你身處大前端得湘,你就不得不擁抱跨端,這是一個不以人意志為轉移的趨勢顿仇。從本質上來講淘正,跨平臺開發(fā)是為了增加業(yè)務代碼的復用率,減少因為要滿足多個平臺的適配開發(fā)而帶來的開發(fā)和維護成本夺欲,從而有效降低開發(fā)成本跪帝。
方案演進
無論大大小小的跨平臺方案,按照其核心的設計思想些阅,可以劃分了三個階段
- Web 容器
基于設備系統(tǒng)原生的瀏覽器組件來實現(xiàn)頁面及業(yè)務功能伞剑。代表方案有:cordova等 - 泛Web容器
采用web標準進行開發(fā),在運行時由原生系統(tǒng)負責渲染繪制市埋。代表方案有:RN黎泣、Weex等 - 自渲染引擎
自帶渲染引擎,客戶端僅需要提供畫布便可以實現(xiàn)業(yè)務功能到UI的多端一致的渲染體驗缤谎。代表方案:Flutter
下面我們逐個分析這三個階段不同的設計思想與各自的優(yōu)勢
Web容器
Web 容器的方案抒倚,是最簡單也最易操作的方案,主要采用原生系統(tǒng)內嵌的瀏覽器控件(Android的WebView坷澡,iOS的WKWebView)的方式渲染H5頁面托呕。客戶端與HT定義好交互的協(xié)議,將一些原生系統(tǒng)能力暴露給H5通過js來調起项郊,也就是大家說的 JSBridge馅扣。
web容器的交互設計可以通過下圖來直觀提現(xiàn)
這種方案最終的渲染方還是瀏覽器,一個H5頁面呈現(xiàn)出來是要經過較為復雜的過程着降,我們可以陳列下最基礎的加載過程差油,就可以知道這個過程的復雜性。
- 瀏覽器控件加載 HTML5 頁面的 HTML 主文檔任洞。
- 加載過程中遇到外部 CSS 文件蓄喇,瀏覽器另外發(fā)出一個請求,來獲取 CSS 文件交掏。
- 遇到圖片資源妆偏,瀏覽器也會另外發(fā)出一個請求,來獲取圖片資源耀销。這是異步請求楼眷,并不會影響 HTML 文檔的加載。
- 加載過程中遇到 JavaScript 文件熊尉,由于 JavaScript 代碼可能會修改 DOM 樹罐柳,因此 HTML 文檔會掛起渲染(加載解析渲染同步)的線程,直到 JavaScript 文件加載解析并執(zhí)行完畢狰住,才可以恢復 HTML 文檔的渲染線程张吉。
- JavaScript 代碼中有用到 CSS 文件中的屬性樣式,于是阻塞催植,等待 CSS 加載完畢才能恢復執(zhí)行肮蛹。
從這個過程我們可以看出,一個完成的H5頁面的呈現(xiàn)要經過瀏覽器控件的加載创南、解析和渲染三大過程伦忠,性能消耗和呈現(xiàn)效率相比原生頁面都有很大的負面增加。雖然Web容器方案開發(fā)體驗友好稿辙,跨平臺兼容性強等優(yōu)勢昆码,但需要承載大量的與Web指定的協(xié)議標準,會導致容器過于笨重邻储,而且較難實現(xiàn)復雜交互和呈現(xiàn)較好的用戶體驗
泛Web容器
泛Web容器的方案優(yōu)化了Web容器方案的瀏覽器加載赋咽、解析和渲染這三大過程,把影響它們獨立運行的 Web 標準進行了裁剪吨娜,以相對簡單的方式支持了構建移動端頁面必要的 Web 標準(如 Flexbox 等)脓匿,也保證了便捷的前端開發(fā)體驗;同時宦赠,這個時代的解決方案基本上完全放棄了瀏覽器控件渲染陪毡,而是采用原生自帶的 UI 組件實現(xiàn)代替了核心的渲染引擎米母,僅保持必要的基本控件渲染能力,從而使得渲染過程更加簡化毡琉,也保證了良好的渲染性能爱咬。也就是說,在泛 Web 容器時代绊起,我們仍然采用前端友好的 JavaScript 進行開發(fā),整體加載燎斩、渲染機制大大簡化虱歪,并且由原生接管繪制,即將原生系統(tǒng)作為渲染的后端栅表,為依托于 JavaScript 虛擬機的 JavaScript 代碼提供所需要的 UI 控件的實體笋鄙。這,也是現(xiàn)在絕大部分跨平臺框架的思路怪瓶。RN和Weex就是采用了這種設計方案萧落。
為了追求更好的性能體驗,進一步位置方案的簡單可擴展性洗贰,一些公司已經放棄Web標準找岖。放棄JS的動態(tài)執(zhí)行能力,而自研一套原生的DSL解析器來實現(xiàn)跨端方案敛滋,例如天貓许布、美團、滴滴等绎晃。
自渲染引擎
泛 Web 容器方案使用原生控件承載界面渲染蜜唾,解決了不少性能問題,但同時也帶來了新的問題庶艾。拋開框架本身需要處理大量平臺相關的邏輯外袁余,隨著系統(tǒng)版本變化和 API 的變化,我們還需要處理不同平臺的原生控件渲染能力差異咱揍,修復各類奇奇怪怪的 Bug颖榜。始終需要 Follow Native 的思維方式,而Flutter 則使用了一種全新的思路述召,即從頭到尾重寫一套跨平臺的 UI 框架朱转,包括渲染邏輯,甚至是開發(fā)語言积暖。
- 渲染引擎依靠跨平臺的 Skia 圖形庫來實現(xiàn)藤为,Skia 引擎會將使用 Dart 構建的抽象的視圖結構數(shù)據(jù)加工成 GPU 數(shù)據(jù),交由 OpenGL 最終提供給 GPU 渲染夺刑,至此完成渲染閉環(huán)缅疟,因此可以在最大程度上保證一款應用在不同平臺分别、不同設備上的體驗一致性。
-
開發(fā)語言選用的是同時支持 JIT(Just-in-Time存淫,即時編譯)和 AOT(Ahead-of-Time耘斩,預編譯)的 Dart,不僅保證了開發(fā)效率桅咆,更提升了執(zhí)行效率(比使用 JavaScript 開發(fā)的泛 Web 容器方案要高得多)括授。
通過這樣的思路,F(xiàn)lutter 可以盡可能地減少不同平臺之間的差異, 同時保持和原生開發(fā)一樣的高性能岩饼。Flutter 成了三類跨平臺移動開發(fā)方案中最靈活的那個荚虚,目前也是熱度相對較高的跨平臺方案。
我們的選擇
對比三種方案最具代表的框架籍茧,我們可以對比他們不同的優(yōu)劣
我們在做技術選型時版述,要從團隊規(guī)模、開發(fā)效率寞冯、技術棧渴析、性能表現(xiàn)、維護成本和社區(qū)生態(tài)來進行綜合考慮吮龄。比如俭茧,是否必須支持動態(tài)化?是只解決 Android漓帚、iOS 的跨端問題恢恼,還是要包括 Web?對性能要求如何胰默?對多端體驗的絕對一致性和維護成本是否有強訴求场斑?社區(qū)是否足夠活躍,能夠交流更多的疑難問題和解決方案牵署,這些都是我們要考慮的漏隐。因為一旦選型后,業(yè)務的推動過程中奴迅,這些問題點最終都是要自己消化掉的青责。判斷一個技術是否能成為未來大前端主流技術發(fā)展的趨勢,主要看這個技術是否能減少對底層宿主環(huán)境的依賴取具,隔離各終端系統(tǒng)差異脖隶,能否從原理和運行機制及生態(tài)有領先同類產品的表現(xiàn),向開發(fā)者提供統(tǒng)一而標準化的能力暇检。