跨平臺技術主要爲三類:前端
Cordova
、Ionic
、微信小程序
)React Native
、Weex
、快應用
)QT for mobile
、Flutter
)這類框架主要原理就是將APP的一部分須要動態變更的內容經過H5來實現,經過原生的網頁加載控件WebView (Android
)或WKWebView
(iOS)來加載(之後若無特殊說明,咱們用WebView
來統一指代android
和iOS
中的網頁加載控件)。這樣以來,H5部分是能夠隨時改變而不用發版,動態化需求能知足;同時,因爲h5代碼只須要一次開發,就能同時在Android和iOS兩個平臺運行,這也能夠減少開發成本,也就是說,H5部分功能越多,開發成本就越小。咱們稱這種h5+原生的開發模式爲混合開發 ,採用混合模式開發的APP咱們稱之爲混合應用
或Hybrid APP
,若是一個應用的大多數功能都是H5
實現的話,咱們稱其爲Web APP
。vue
目前混合開發框架的典型表明有:Cordova
、Ionic
和微信小程序
,值得一提的是微信小程序
目前是在webview
中渲染的,並不是原生渲染,但未來有可能會採用原生渲染。python
如以前所述,原生開發能夠訪問平臺全部功能,而混合開發中,H5代碼是運行在WebView中,而WebView實質上就是一個瀏覽器內核,其JavaScript依然運行在一個權限受限的沙箱中,因此對於大多數系統能力都沒有訪問權限,如沒法訪問文件系統、不能使用藍牙等。因此,對於H5不能實現的功能,都須要原生去作。而混合框架通常都會在原生代碼中預先實現一些訪問系統能力的API, 而後暴露給WebView以供JavaScript調用,這樣一來,WebView就成爲了JavaScript與原生API之間通訊的橋樑,主要負責JavaScript與原生之間傳遞調用消息,而消息的傳遞必須遵照一個標準的協議,它規定了消息的格式與含義,咱們把依賴於WebView的用於在JavaScript與原生之間通訊並實現了某種消息傳輸協議的工具稱之爲WebView JavaScript Bridge, 簡稱 JsBridge,它也是混合開發框架的核心。android
混合應用的優勢是動態內容是H5,web技術棧,社區及資源豐富,缺點是性能很差,對於複雜用戶界面或動畫,WebView不堪重任。web
React Native (簡稱RN)是Facebook於2015年4月開源的跨平臺移動應用開發框架,是Facebook早先開源的JS框架 。算法
文檔對象模型(Document Object Model,簡稱DOM),是W3C組織推薦的處理可擴展標誌語言的標準編程接口,一種獨立於平臺和語言的方式訪問和修改一個文檔的內容和結構。換句話說,這是表示和處理一個HTML或XML文檔的標準接口。簡單來講,DOM就是文檔樹,與用戶界面控件樹對應,在前端開發中一般指HTML對應的渲染樹,但廣義的DOM也能夠指Android中的XML佈局文件對應的控件樹,而術語DOM操做就是指直接來操做渲染樹(或控件樹), 所以,能夠看到其實DOM樹和控件樹是等價的概念,只不過前者經常使用於Web開發中,然後者經常使用於原生開發中。編程
值得注意的是
,在第二步中,狀態變化後React框架並不會
當即去計算並渲染DOM樹的變化部分,相反,React會在DOM的基礎上創建一個抽象層
,即虛擬DOM樹
,對數據和狀態所作的任何改動,都會被自動
且高效
的同步到虛擬DOM
,最後再批量同步到真實DOM
中,而不是每次改變都去操做一下DOM。爲何不能每次改變都直接去操做DOM樹?這是由於在瀏覽器中每一次DOM操做都有可能引發瀏覽器的重繪
或迴流
:小程序
重繪界面
: 若是DOM只是外觀風格發生變化,如顏色變化,會致使瀏覽器重繪界面。微信小程序
迴流
: 若是DOM樹的結構發生變化,如尺寸、佈局、節點隱藏等致使,瀏覽器就須要迴流(及從新排版佈局)。瀏覽器
而瀏覽器的重繪
和迴流
都是比較昂貴的操做,若是每一次改變都直接對DOM進行操做,這會帶來性能問題,而批量操做只會觸發一次DOM更新。
JavaScriptCore 是一個JavaScript解釋器,它在React Native中主要有兩個做用:
而RN中將虛擬DOM映射爲原生控件的過程當中分兩步:
React Native是原生控件渲染,因此性能會比混合應用中H5好不少,同時React Native是Web開發技術棧,也只需維護一份代碼,一樣是跨平臺框架。
Weex是阿里巴巴於2016年發佈的跨平臺移動端開發框架,思想及原理和React Native相似,最大的不一樣是語法層面,Weex支持Vue語法和Rax語法,Rax 的 DSL(Domain Specific Language) 語法是基於 React JSX 語法而創造。與 React 不一樣,在 Rax 中 JSX 是必選的,它不支持經過其它方式建立組件,因此學習 JSX 是使用 Rax 的必要基礎。而React Native只支持JSX語法。
快應用是華爲、小米、OPPO、魅族等國內9大主流手機廠商共同制定的輕量級應用標準,目標直指微信小程序
。它也是採用JavaScript語言開發,原生控件渲染,與React Native
和Weex
相比主要有兩點不一樣:
快應用自身不支持Vue或React語法,其採用原生JavaScript開發,其開發框架和微信小程序很像,值得一提的是小程序目前已經可使用Vue語法開發(mpvue),從原理上來說,Vue的語法也能夠移植到快應用上。
React Native和Weex的渲染/排版引擎是集成到框架中的,每個APP都須要打包一份,安裝包體積較大;而快應用渲染/排版引擎是集成到ROM中的,應用中無需打包,安裝包體積小,正因如此,快應用才能在保證性能的同時作到快速分發。
JavaScript開發+原生渲染的方式主要優勢以下:
採用Web開發技術棧,社區龐大、上手快、開發成本相對較低。
原生渲染,性能相比H5提升不少。
動態化較好,支持熱更新。
不足:
渲染時須要JavaScript和原生之間通訊,在有些場景如拖動可能會由於通訊頻繁致使卡頓。
JavaScript爲腳本語言,執行時須要JIT(Just In Time),執行效率和AOT(Ahead Of Time)代碼仍有差距。
因爲渲染依賴原生控件,不一樣平臺的控件須要單獨維護,而且當系統更新時,社區控件可能會滯後;除此以外,其控件系統也會受到原生UI系統限制,例如,在Android中,手勢衝突消歧規則是固定的,這在使用不一樣人寫的控件嵌套時,手勢衝突問題將會變得很是棘手。
自繪UI+原生。這種技術的思路是,經過在不一樣平臺實現一個統一接口的渲染引擎來繪製UI,而不依賴系統原生控件,因此能夠作到不一樣平臺UI的一致性。注意,自繪引擎解決的是UI的跨平臺問題,若是涉及其它系統能力調用,依然要涉及原生開發。這種平臺技術的優勢以下:
性能高;因爲自繪引擎是直接調用系統API來繪製UI,因此性能和原生控件接近。
靈活、組件庫易維護、UI外觀保真度和一致性高;因爲UI渲染不依賴原生控件,也就不須要根據不一樣平臺的控件單獨維護一套組件庫,因此代碼容易維護。因爲組件庫是同一套代碼、同一個渲染引擎,因此在不一樣平臺,組件顯示外觀能夠作到高保真和高一致性;另外,因爲不依賴原生控件,也就不會受原生布局系統的限制,這樣佈局系統會很是靈活。
不足:
Flutter正是實現一套自繪引擎,並擁有一套本身的UI佈局系統。不過,自繪製引擎的思路並非什麼新概念
,Flutter並非第一個嘗試這麼作的,在它以前有一個典型的表明,即大名鼎鼎的QT。
Qt是一個1991年由Qt Company開發的跨平臺C++圖形用戶界面應用程序開發框架。2008年,Qt Company科技被諾基亞公司收購,Qt也所以成爲諾基亞旗下的編程語言工具。2012年,Qt被Digia收購。2014年4月,跨平臺集成開發環境Qt Creator 3.1.0正式發佈,實現了對於iOS的徹底支持,新增WinRT、Beautifier等插件,廢棄了無Python接口的GDB調試支持,集成了基於Clang的C/C++代碼模塊,並對Android支持作出了調整,至此實現了全面支持iOS、Android、WP,它提供給應用程序開發者構建圖形用戶界面所需的全部功能。可是,QT雖然在PC端得到了巨大成功,備受社區追捧,然而其在移動端卻表現不佳,在近幾年,雖然偶爾能聽到QT的聲音,但一直很弱,不管QT自己技術如何、設計思想如何,但事實上終究是敗了,究其緣由,筆者認爲主要有四:
QT移動開發社區過小,學習資料不足,生態很差。
官方推廣不利,支持不夠。
移動端發力較晚,市場已被其它動態化框架佔領(Hybrid和RN)。
在移動開發中,C++開發和Web開發棧相比有着先天的劣勢,直接結果就是QT開發效率過低。
基於此四點,儘管QT是移動端開發跨平臺自繪引擎的先驅,但卻成爲了烈士。
Flutter 是 Google推出並開源的移動應用開發框架,主打跨平臺、高保真、高性能。開發者能夠經過 Dart語言開發 App,一套代碼同時運行在 iOS 和 Android平臺。 Flutter提供了豐富的組件、接口,開發者能夠很快地爲 Flutter添加 native擴展。同時 Flutter還使用 Native引擎渲染視圖,這無疑能爲用戶提供良好的體驗。
2017 年 Google I/O 大會上,Google 首次推出了一款新的用於建立跨平臺、高性能的移動應用框架。
2018年2月,Flutter發佈了第一個Beta版本,同年五月, 在2018年Google I/O 大會上,Flutter 更新到了 beta 3 版本。
2018年6月,Flutter發佈了首個預覽版本,這意味着 Flutter 進入了正式版(1.0)發佈前的最後階段。
Flutter與用於構建移動應用程序的其它大多數框架不一樣,由於Flutter既不使用WebView,也不使用操做系統的原生控件。 相反,Flutter使用本身的高性能渲染引擎來繪製widget。這樣不只能夠保證在Android和iOS上UI的一致性,並且也能夠避免對原生控件依賴而帶來的限制及高昂的維護成本。
Flutter使用Skia做爲其2D渲染引擎,Skia是Google的一個2D圖形處理函數庫,包含字型、座標轉換,以及點陣圖都有高效能且簡潔的表現,Skia是跨平臺的,並提供了很是友好的API,目前Google Chrome瀏覽器和Android均採用Skia做爲其繪圖引擎。
目前Flutter目前默認支持iOS、Android、Fuchsia(Google新的自研操做系統)三個移動平臺。但Flutter亦可支持Web開發(Flutter for web)和PC開發,本書的示例和介紹主要是基於iOS和Android平臺的,其它平臺讀者能夠自行了解。
Flutter高性能主要靠兩點來保證,首先,Flutter APP採用Dart語言開發。Dart在 JIT(即時編譯)模式下,速度與 JavaScript基本持平。可是 Dart支持 AOT,當以 AOT模式運行時,JavaScript便遠遠追不上了。速度的提高對高幀率下的視圖數據計算頗有幫助。其次,Flutter使用本身的渲染引擎來繪製UI,佈局數據等由Dart語言直接控制,因此在佈局過程當中不須要像RN那樣要在JavaScript和Native之間通訊,這在一些滑動和拖動的場景下具備明顯優點,由於在滑動和拖動過程每每都會引發佈局發生變化,因此JavaScript須要和Native之間不停的同步佈局信息,這和在瀏覽器中要JavaScript頻繁操做DOM所帶來的問題是相同的,都會帶來比較可觀的性能開銷。
這是一個頗有意思,但也頗有爭議的問題,在瞭解Flutter
爲何選擇了 Dart
而不是 JavaScript
以前咱們先來介紹兩個概念:JIT
和AOT
。
目前,程序主要有兩種運行方式:靜態編譯
與動態解釋
。
AOT
: 靜態編譯的程序在執行前所有被翻譯爲機器碼,一般將這種類型稱爲AOT (Ahead of time)
即 「提早編譯
」;
JIT
: 而解釋執行的則是一句一句邊翻譯邊運行,一般將這種類型稱爲JIT(Just-in-time)
即「即時編譯
」。
AOT
程序的典型表明是用C/C++
開發的應用,它們必須在執行前編譯
成機器碼,而JIT
的表明則很是多,如JavaScript
、python
等,事實上,全部腳本語言都支持JIT
模式。
但須要注意的是JIT
和AOT
指的是程序運行方式
,和編程語言並不是強關聯的,有些語言既能夠以JIT
方式運行也能夠以AOT
方式運行,如Java
、Python
,它們能夠在第一次執行時編譯成中間字節碼
、而後在以後執行時能夠直接執行字節碼,也許有人會說,中間字節碼並不是機器碼,在程序執行時仍然須要動態將字節碼
轉爲機器碼
,是的,這沒有錯,不過一般咱們區分
是否爲AOT
的標準就是看代碼在執行以前是否須要編譯
,只要須要編譯,不管其編譯產物是字節碼
仍是機器碼
,都屬於AOT
。在此,讀者沒必要糾結於概念,概念就是爲了傳達精神而發明的,只要讀者可以理解其原理便可,得其神忘其形。
如今咱們看看Flutter
爲何選擇Dart
語言?筆者根據官方解釋以及本身對Flutter
的理解總結了如下幾條(因爲其它跨平臺框架都將JavaScript
做爲其開發語言,因此主要將Dart
和JavaScript
作一個對比):
Dart
運行時和編譯器支持Flutter的兩個關鍵特性的組合:
基於JIT
的快速開發週期:Flutter
在開發階段採用,採用JIT
模式,這樣就避免了每次改動都要進行編譯,極大的節省了開發時間;
基於AOT
的發佈包: Flutter
在發佈時能夠經過AOT
生成高效的ARM
代碼以保證應用性能。而JavaScript
則不具備這個能力。
Flutter旨在提供流暢、高保真的的UI體驗。爲了實現這一點,Flutter中須要可以在每一個動畫幀中運行大量的代碼。這意味着須要一種既能提供高性能的語言,而不會出現會丟幀的週期性暫停,而Dart支持AOT,在這一點上能夠作的比JavaScript更好。
Flutter框架使用函數式流,這使得它在很大程度上依賴於底層的內存分配器。所以,擁有一個可以有效地處理瑣碎任務的內存分配器將顯得十分重要,在缺少此功能的語言中,Flutter將沒法有效地工做。固然Chrome V8的JavaScript引擎在內存分配上也已經作的很好,事實上Dart開發團隊的不少成員都是來自Chrome團隊的,因此在內存分配上Dart並不能做爲超越JavaScript的優點,而對於Flutter來講,它須要這樣的特性,而Dart也正好知足而已。
因爲Dart是類型安全的語言,支持靜態類型檢測,因此能夠在編譯前發現一些類型的錯誤,並排除潛在問題,這一點對於前端開發者來講可能會更具備吸引力。與之不一樣的,JavaScript是一個弱類型語言,也所以前端社區出現了不少給JavaScript代碼添加靜態類型檢測的擴展語言和工具,如:微軟的TypeScript以及Facebook的Flow。相比之下,Dart自己就支持靜態類型,這是它的一個重要優點。
看似不起眼,實則舉足輕重。因爲有Dart團隊的積極投入,Flutter團隊能夠得到更多、更方便的支持,正如Flutter官網所述「咱們正與Dart社區進行密切合做,以改進Dart在Flutter中的使用。例如,當咱們最初採用Dart時,該語言並無提供生成原生二進制文件的工具鏈(這對於實現可預測的高性能具備很大的幫助),可是如今它實現了,由於Dart團隊專門爲Flutter構建了它。一樣,Dart VM以前已經針對吞吐量進行了優化,但團隊如今正在優化VM的延遲時間,這對於Flutter的工做負載更爲重要。」
技術類型 UI渲染方式 性能 開發效率 動態化 框架表明 H5+原生 WebView渲染 通常 高 支持 Cordova、Ionic JavaScript+原生渲染 原生控件渲染 好 中 支持 RN、Weex 自繪UI+原生 調用系統API渲染 好 Flutter高, QT低 默認不支持 QT、Flutter
技術類型級 | UI渲染方式 | 性能 | 開發效率 | 動態化 | 框架表明 |
---|---|---|---|---|---|
H5+原生 | WebView渲染 | 通常 | 高 | 支持 | Cordova、Ionic |
JavaScript+原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex |
自繪UI+原生 | 調用系統API渲染 | 好 | F 高 QT低 | 默認不支持 | QT、Flutter |
上表中開發語言主要指UI的開發語言。而開發效率,是指整個開發週期的效率,包括編碼時間、調試時間、以及排錯、兼容時間。
動態化
:主要指是否支持動態下發代碼
和是否支持熱更新
。
值得注意的是
:Flutter的Release
包默認是使用Dart AOT模式編譯
的,因此不支持動態
化;
可是Dart
還有JIT
或snapshot
運行方式,這些模式都是支持動態化
的。