本節(jié)將主要介紹一下移動開發(fā)技術(shù)的進化歷程,主要是想讓讀者知道Flutter技術(shù)出現(xiàn)的背景。筆者認為,了解一門新技術(shù)出現(xiàn)的背景是非常重要的,因為只有了解之前是什么樣的,才能理解為什么會是現(xiàn)在這樣。
原生應(yīng)用程序是指某一個移動平臺(比如iOS或安卓)所特有的應(yīng)用,使用相應(yīng)平臺支持的開發(fā)工具和語言,并直接調(diào)用系統(tǒng)提供的SDK API。比如Android原生應(yīng)用就是指使用Java或Kotlin語言直接調(diào)用Android SDK開發(fā)的應(yīng)用程序;而iOS原生應(yīng)用就是指通過Objective-C或Swift語言直接調(diào)用iOS SDK開發(fā)的應(yīng)用程序。原生開發(fā)有以下主要優(yōu)勢:
主要缺點:
在移動互聯(lián)網(wǎng)發(fā)展初期,業(yè)務(wù)場景并不復(fù)雜,原生開發(fā)還可以應(yīng)對產(chǎn)品需求迭代。 但近幾年,隨著物聯(lián)網(wǎng)時代到來、移動互聯(lián)網(wǎng)高歌猛進,日新月異,在很多業(yè)務(wù)場景中,傳統(tǒng)的純原生開發(fā)已經(jīng)不能滿足日益增長的業(yè)務(wù)需求。主要表現(xiàn)在:
總結(jié)一下,純原生開發(fā)主要面臨動態(tài)化和開發(fā)成本兩個問題,而針對這兩個問題,誕生了一些跨平臺的動態(tài)化框架。
針對原生開發(fā)面臨問題,人們一直都在努力尋找好的解決方案,而時至今日,已經(jīng)有很多跨平臺框架(注意,本書中所指的“跨平臺”若無特殊說明,即特指Android和iOS兩個平臺),根據(jù)其原理,主要分為三類:
在接下來的章節(jié)中我們逐個來看看這三類框架的原理及優(yōu)缺點。
這類框架主要原理就是將APP的一部分需要動態(tài)變動的內(nèi)容通過H5來實現(xiàn),通過原生的網(wǎng)頁加載控件WebView (Android)或WKWebView(iOS)來加載(以后若無特殊說明,我們用WebView來統(tǒng)一指代android和iOS中的網(wǎng)頁加載控件)。這樣以來,H5部分是可以隨時改變而不用發(fā)版,動態(tài)化需求能滿足;同時,由于h5代碼只需要一次開發(fā),就能同時在Android和iOS兩個平臺運行,這也可以減小開發(fā)成本,也就是說,H5部分功能越多,開發(fā)成本就越小。我們稱這種h5+原生的開發(fā)模式為混合開發(fā) \ ,采用混合模式開發(fā)的APP我們稱之為混合應(yīng)用或Hybrid APP ,如果一個應(yīng)用的大多數(shù)功能都是H5實現(xiàn)的話,我們稱其為Web APP 。
目前混合開發(fā)框架的典型代表有:Cordova、Ionic 和微信小程序,值得一提的是微信小程序目前是在webview中渲染的,并非原生渲染,但將來有可能會采用原生渲染。
如之前所述,原生開發(fā)可以訪問平臺所有功能,而混合開發(fā)中,H5代碼是運行在WebView中,而WebView實質(zhì)上就是一個瀏覽器內(nèi)核,其JavaScript依然運行在一個權(quán)限受限的沙箱中,所以對于大多數(shù)系統(tǒng)能力都沒有訪問權(quán)限,如無法訪問文件系統(tǒng)、不能使用藍牙等。所以,對于H5不能實現(xiàn)的功能,都需要原生去做。而混合框架一般都會在原生代碼中預(yù)先實現(xiàn)一些訪問系統(tǒng)能力的API, 然后暴露給WebView以供JavaScript調(diào)用,這樣一來,WebView就成為了JavaScript與原生API之間通信的橋梁,主要負責(zé)JavaScript與原生之間傳遞調(diào)用消息,而消息的傳遞必須遵守一個標準的協(xié)議,它規(guī)定了消息的格式與含義,我們把依賴于WebView的用于在JavaScript與原生之間通信并實現(xiàn)了某種消息傳輸協(xié)議的工具稱之為WebView JavaScript Bridge, 簡稱 JsBridge,它也是混合開發(fā)框架的核心。
下面我們以Android為例,實現(xiàn)一個獲取手機型號的原生API供JavaScript調(diào)用。在這個示例中將展示JavaScript調(diào)用原生API的流程,讀者可以直觀的感受一下調(diào)用流程。我們選用筆者在Github上開源的dsBridge作為JsBridge來進行通信。dsBridge是一個支持同步調(diào)用的跨平臺的JsBridge,此示例中只使用其同步調(diào)用功能。
getPhoneModel
class JSAPI {
@JavascriptInterface
public Object getPhoneModel(Object msg) {
return Build.MODEL;
}
}
import wendu.dsbridge.DWebView
...
//DWebView繼承自WebView,由dsBridge提供
DWebView dwebView = (DWebView) findViewById(R.id.dwebview);
//注冊原生API到JsBridge
dwebView.addJavascriptObject(new JsAPI(), null);
var dsBridge = require("dsbridge")
//直接調(diào)用原生API `getPhoneModel`
var model = dsBridge.call("getPhoneModel");
//打印機型
console.log(model);
上面示例演示了JavaScript調(diào)用原生API的過程,同樣的,一般來說優(yōu)秀的JsBridge也支持原生調(diào)用JavaScript,dsBridge也是支持的,如果您感興趣,可以去github dsBridge項目主頁查看。
現(xiàn)在,我們回頭來看一下,混合應(yīng)用無非就是在第一步中預(yù)先實現(xiàn)一系列API供JavaScript調(diào)用,讓JavaScript有訪問系統(tǒng)的能力,看到這里,我相信你也可以自己實現(xiàn)一個混合開發(fā)框架了。
混合應(yīng)用的優(yōu)點是動態(tài)內(nèi)容是H5,web技術(shù)棧,社區(qū)及資源豐富,缺點是性能不好,對于復(fù)雜用戶界面或動畫,WebView不堪重任。
本篇主要介紹一下 JavaScript開發(fā)+原生渲染的跨平臺框架原理。
React Native (簡稱RN)是Facebook于2015年4月開源的跨平臺移動應(yīng)用開發(fā)框架,是Facebook早先開源的JS框架 React 在原生移動應(yīng)用平臺的衍生產(chǎn)物,目前支持iOS和Android兩個平臺。RN使用Javascript語言,類似于HTML的JSX,以及CSS來開發(fā)移動應(yīng)用,因此熟悉Web前端開發(fā)的技術(shù)人員只需很少的學(xué)習(xí)就可以進入移動應(yīng)用開發(fā)領(lǐng)域。
由于RN和React原理相通,并且Flutter也是受React啟發(fā),很多思想也都是相通的,萬丈高樓平地起,我們有必要深入了解一下React原理。React是一個響應(yīng)式的Web框架,我們先了解一下兩個重要的概念:DOM樹與響應(yīng)式編程。
文檔對象模型(Document Object Model,簡稱DOM),是W3C組織推薦的處理可擴展標志語言的標準編程接口,一種獨立于平臺和語言的方式訪問和修改一個文檔的內(nèi)容和結(jié)構(gòu)。換句話說,這是表示和處理一個HTML或XML文檔的標準接口。簡單來說,DOM就是文檔樹,與用戶界面控件樹對應(yīng),在前端開發(fā)中通常指HTML對應(yīng)的渲染樹,但廣義的DOM也可以指Android中的XML布局文件對應(yīng)的控件樹,而術(shù)語DOM操作就是指直接來操作渲染樹(或控件樹), 因此,可以看到其實DOM樹和控件樹是等價的概念,只不過前者常用于Web開發(fā)中,而后者常用于原生開發(fā)中。
React中提出一個重要思想:狀態(tài)改變則UI隨之自動改變,而React框架本身就是響應(yīng)用戶狀態(tài)改變的事件而執(zhí)行重新構(gòu)建用戶界面的工作,這就是典型的響應(yīng)式編程范式,下面我們總結(jié)一下React中響應(yīng)式原理:
值得注意的是,在第二步中,狀態(tài)變化后React框架并不會立即去計算并渲染DOM樹的變化部分,相反,React會在DOM的基礎(chǔ)上建立一個抽象層,即虛擬DOM樹,對數(shù)據(jù)和狀態(tài)所做的任何改動,都會被自動且高效的同步到虛擬DOM,最后再批量同步到真實DOM中,而不是每次改變都去操作一下DOM。為什么不能每次改變都直接去操作DOM樹?這是因為在瀏覽器中每一次DOM操作都有可能引起瀏覽器的重繪或回流:
而瀏覽器的重繪和回流都是比較昂貴的操作,如果每一次改變都直接對DOM進行操作,這會帶來性能問題,而批量操作只會觸發(fā)一次DOM更新。
思考題:Diff操作和DOM批量更新難道不應(yīng)該是瀏覽器的職責(zé)嗎?第三方框架中去做合不合適?
此處需要有一張插圖
上文已經(jīng)提到React Native 是React 在原生移動應(yīng)用平臺的衍生產(chǎn)物,那兩者主要的區(qū)別是什么呢?其實,主要的區(qū)別在于虛擬DOM映射的對象是什么?React中虛擬DOM最終會映射為瀏覽器DOM樹,而RN中虛擬DOM會通過 JavaScriptCore 映射為原生控件樹。
JavaScriptCore 是一個JavaScript解釋器,它在React Native中主要有兩個作用:
而RN中將虛擬DOM映射為原生控件的過程中分兩步:
至此,React Native 便實現(xiàn)了跨平臺。 相對于混合應(yīng)用,由于React Native是原生控件渲染,所以性能會比混合應(yīng)用中H5好很多,同時React Native使用了Web開發(fā)技術(shù)棧,也只需維護一份代碼,同樣是跨平臺框架。
Weex是阿里巴巴于2016年發(fā)布的跨平臺移動端開發(fā)框架,思想及原理和React Native類似,最大的不同是語法層面,Weex支持Vue語法和Rax語法,Rax 的 DSL(Domain Specific Language) 語法是基于 React JSX 語法而創(chuàng)造。與 React 不同,在 Rax 中 JSX 是必選的,它不支持通過其它方式創(chuàng)建組件,所以學(xué)習(xí) JSX 是使用 Rax 的必要基礎(chǔ)。而React Native只支持JSX語法。
快應(yīng)用是華為、小米、OPPO、魅族等國內(nèi)9大主流手機廠商共同制定的輕量級應(yīng)用標準,目標直指微信小程序。它也是采用JavaScript語言開發(fā),原生控件渲染,與React Native和Weex相比主要有兩點不同:
JavaScript開發(fā)+原生渲染的方式主要優(yōu)點如下:
不足:
在本篇中,我們看看最后一種跨平臺技術(shù):自繪UI+原生。這種技術(shù)的思路是,通過在不同平臺實現(xiàn)一個統(tǒng)一接口的渲染引擎來繪制UI,而不依賴系統(tǒng)原生控件,所以可以做到不同平臺UI的一致性。注意,自繪引擎解決的是UI的跨平臺問題,如果涉及其它系統(tǒng)能力調(diào)用,依然要涉及原生開發(fā)。這種平臺技術(shù)的優(yōu)點如下:
不足:
也許你已經(jīng)猜到Flutter就屬于這一類跨平臺技術(shù),沒錯,F(xiàn)lutter正是實現(xiàn)一套自繪引擎,并擁有一套自己的UI布局系統(tǒng)。不過,自繪制引擎的思路并不是什么新概念,F(xiàn)lutter并不是第一個嘗試這么做的,在它之前有一個典型的代表,即大名鼎鼎的QT。
Qt是一個1991年由Qt Company開發(fā)的跨平臺C++圖形用戶界面應(yīng)用程序開發(fā)框架。2008年,Qt Company科技被諾基亞公司收購,Qt也因此成為諾基亞旗下的編程語言工具。2012年,Qt被Digia收購。2014年4月,跨平臺集成開發(fā)環(huán)境Qt Creator 3.1.0正式發(fā)布,實現(xiàn)了對于iOS的完全支持,新增WinRT、Beautifier等插件,廢棄了無Python接口的GDB調(diào)試支持,集成了基于Clang的C/C++代碼模塊,并對Android支持做出了調(diào)整,至此實現(xiàn)了全面支持iOS、Android、WP,它提供給應(yīng)用程序開發(fā)者構(gòu)建圖形用戶界面所需的所有功能。但是,QT雖然在PC端獲得了巨大成功,備受社區(qū)追捧,然而其在移動端卻表現(xiàn)不佳,在近幾年,雖然偶爾能聽到QT的聲音,但一直很弱,無論QT本身技術(shù)如何、設(shè)計思想如何,但事實上終究是敗了,究其原因,筆者認為主要有四:
第一:QT移動開發(fā)社區(qū)太小,學(xué)習(xí)資料不足,生態(tài)不好。
第二:官方推廣不利,支持不夠。
第三:移動端發(fā)力較晚,市場已被其它動態(tài)化框架占領(lǐng)(Hybrid和RN)。
第四:在移動開發(fā)中,C++開發(fā)和Web開發(fā)棧相比有著先天的劣勢,直接結(jié)果就是QT開發(fā)效率太低。
基于此四點,盡管QT是移動端開發(fā)跨平臺自繪引擎的先驅(qū),但卻成為了烈士。
“千呼萬喚始出來”,鋪墊這么久,現(xiàn)在終于等到本書的主角出場了!
Flutter是Google發(fā)布的一個用于創(chuàng)建跨平臺、高性能移動應(yīng)用的框架。Flutter和QT mobile一樣,都沒有使用原生控件,相反都實現(xiàn)了一個自繪引擎,使用自身的布局、繪制系統(tǒng)。那么,我們會擔(dān)心,QT mobile面對的問題Flutter是否也一樣,F(xiàn)lutter會不會步入QT mobile后塵,成為另一個烈士?要回到這個問題,我們先來看看Flutter誕生過程:
觀其發(fā)展,在2018年5月份,F(xiàn)lutter 進入了 GitHub stars 排行榜前 100 名,已有 27k star。而今天(2019年5月29日),已經(jīng)有65K的Star。經(jīng)歷了短短2年多的時間,F(xiàn)lutter 生態(tài)系統(tǒng)得以快速增長,由此可見,F(xiàn)lutter在開發(fā)者中受到了熱烈的歡迎,其未來發(fā)展值得期待!
現(xiàn)在,我們來和QT mobile做一個對比:
基于以上三點,相信讀者和筆者一樣,F(xiàn)lutter未來如何,心中自有定論。到現(xiàn)在為止,我們已經(jīng)對移動端開發(fā)技術(shù)有了一個全面的了解,接下來我們便要進入本書的主題,你準備好了嗎!
本章主要介紹了目前移動開發(fā)中三種跨平臺技術(shù),現(xiàn)在我們從框架角度對比一下它們,如表1-1所示:
技術(shù)類型 | UI渲染方式 | 性能 | 開發(fā)效率 | 動態(tài)化 | 框架代表 |
---|---|---|---|---|---|
H5+原生 | WebView渲染 | 一般 | 高 | 支持 | Cordova、Ionic |
JavaScript+原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex |
自繪UI+原生 | 調(diào)用系統(tǒng)API渲染 | 好 | Flutter高, QT低 | 默認不支持 | QT、Flutter |
表1-1: 跨平臺技術(shù)對比
上表中開發(fā)語言主要指UI的開發(fā)語言。而開發(fā)效率,是指整個開發(fā)周期的效率,包括編碼時間、調(diào)試時間、以及排錯、兼容時間。動態(tài)化主要指是否支持動態(tài)下發(fā)代碼和是否支持熱更新。值得注意的是Flutter的Release包默認是使用Dart AOT模式編譯的,所以不支持動態(tài)化,但Dart還有JIT或snapshot運行方式,這些模式都是支持動態(tài)化的。
更多建議: