Native App(如下簡稱Native)和Mobile Web(如下簡稱Web)兩者混合開發的產物被稱爲Hybrid App(如下簡稱Hybrid)。Hybrid並非什麼新概念,最先能夠追溯到Symbian時代,直到iOS和Android出現以後才充分展示出價值。javascript
Hybrid既利用了Native App豐富的設備API(Device API),又能擁有Mobile Web的跨平臺、高效開發、快速發佈的能力,對於至關龐大的應用場景而言都是適用的。html
Hybrid優點在於:前端
Web內容能夠作到開發一次,全部平臺生效,諸多產品須要這種能力。html5
iOS平臺,Apple Store平均審覈週期1~2周不等,甚至更長,產品的發佈週期從2周到1月,這對須要快速發佈的產品而言難以接受。java
Android平臺,應用商店衆多,發佈過程煩瑣。雖然能夠應用內升級,可是帶來的問題是新App須要經過應用商店,此外APK體積龐大,2G/3G環境下體驗差。android
Web開發通過20年的發展,已經將結構(HTML)、表現(CSS)、行爲(JavaScript)3部分很好地分離開,在分工協做、開發效率上會具明顯優點。git
Web(HTML5)強調通用性,受限於標準和瀏覽器實現,許多有用的系統功能未能獲得支持(或部分支持)。而Native最大的優點在於設備API的調用能力,只要橋接Native和Web,Web也就可以擁有這種能力。github
Hybrid劣勢表現爲:web
雛形階段大體爲:chrome
「跨平臺」成了Hybrid最大的賣點,以PhoneGap[1]爲首的Hybrid框架陸續出現,帶來了諸多改變。
隨着PhoneGap這類Hybrid框架在全球的流行,一些問題暴露了出來,也正是這些問題的解決,讓Hybrid走向成熟。
以上即是Hybrid的發展概述,從國內最新的資料能夠看出,Hybrid的趨勢也是很是明顯的。從圖8-1能夠看到愈來愈多的開發者決定使用Hybrid(跨平臺技術),最近兩年的總量已經有54%;而接近60%的開發者在Hybrid的技術方案上選擇了PhoneGap。
圖8-1 Hybrid在國內的發展狀況[6]
圖8-2 Hybrid使用狀況
圖8-3 跨平臺特性受關注
圖8-4顯示了Hybrid驚人的增加速度:2013年不管是開發中、已發佈的Hybrid(或HTML App)均相比於2012年出現了超過125%~400%的增加率[8]。
圖8-4 Hybrid增加迅猛[9]
不管Android仍是iOS,實現一個最簡單的Hybrid App只須要幾行代碼:實例化WebView、加載頁面,以後即是頁面自身的代碼。要想實現更爲複雜的、完整的Hybrid還須要很多知識。
Mobile Web開發基礎能夠參考本書第2章,Native App開發基礎已經超出本書的討論範圍,一樣有不少可選擇的書籍,本節來說剩餘的第3個問題 「Native與Web雙向通訊機制」。
不管Android仍是iOS ,Native調用Web(JavaScript) 都有很好的原生支持,如代碼8-1和代碼8-2所示。Android中的調用方式以下,其中webView是Webview的實例。
代碼8-1 Android調用JavaScript
webView.loadUrl("javascript:(function(){ alert(‘ok’); })()」);
iOS中的調用方式以下,其中webView是UIWebview的實例。
代碼8-2 iOS調用JavaScript
[webView stringByEvaluatingJavaScriptFromString: @"alert('ok')" ];
「Native調用Web」本質上是JavaScript腳本的動態執行,在「Web調用Native」的場景下因爲目前Native語言(Java和Objective-C)不容易像JavaScript那樣便於動態執行,因此須要另闢蹊徑。
Android上常見的方式有3種。
代碼8-3 重寫WebViewClient.shouldOverrideUrlLoading
webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading (WebView view, String url){ // TODO解析URL並觸發Native代碼 return true; } });
當頁面內的URL發生變化時,如點擊連接、執行JavaScript(如location.href=」http://」)等均會觸發WebViewClient.shouldOverrideUrlLoading,經過將Web調用Native的數據封裝在URL,再由Native解析數據並執行響應Native方法。
代碼8-4 重寫WebChromeClient.onJsPrompt
webView.setWebChromeClient(new WebChromeClient() { public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // TODO解析message並觸發Native代碼 result.confirm(""); return true; } });
當執行「window.prompt(「{}」)」這樣的JavaScript代碼時,將會觸發WebChromeClient.onJsPrompt。
代碼8-5 WebView.addJavascriptInterface
webView.addJavascriptInterface(new Object() { public void func1() { } public void func2() { } }, "webViewObj");
以上3種方式,最經常使用的是方式2;方式2相比方式1有內置的隊列支持,不會出現高頻訪問數據丟失的狀況;方式3是Android原生方式,可是不如前兩種方式靈活。
iOS中可用的方式相似Android中的WebViewClient.shouldOverrideUrlLoading, 經過監控WebView的URL變化實現Web調用Native,如代碼8-6所示。
代碼8-6 shouldStartLoadWithRequest
- (BOOL)webView:(UIWebView *) webView shouldStartLoadWithRequest: (NSURLRequest *)request navigationType: (UIWebViewNavigationType)navigationType { }
有了前兩節的知識,能夠實現一個通用模塊(Bridge)來維護不一樣平臺上的「Web與Native雙向通訊機制」功能。如圖8-5所示爲Web調用Native的Bridge時序圖。
圖8-5 Web調用Native的Bridge時序圖
Web調用Native的實現原理以下。
圖8-6 Native調用Web時的Bridge時序圖
能夠看到,Bridge實現「Native調用Web」是相似的。
筆者已經在Android上實現了完整的Bridge[10],Bridge由JavaScript實現能夠運行在Android和iOS的WebView中,同時也很是容易擴展到Windows Phone等新平臺,如代碼8-7所示。
代碼8-7 bridge.js
(function(window) { var DEBUG = true; var callbacks = {}; var guid = 0; var ua = navigator.userAgent; // TODO精確性待改進 var ANDROID = /android/i.test(ua); var IOS = /iphone|ipad/i.test(ua); var WP = /windows phone/i.test(ua); //ANDROID = 0; IOS = 1; /** * 方便在各個平臺中看到完整的log */ function log() { if (DEBUG) { console.log.call(console, Array.prototype.join.call(arguments, ' ')); } } /** * 平臺相關的Web與Native單向通訊方法 */ function invoke(cmd) { log('invoke', cmd); if (ANDROID) { prompt(cmd); } else if (IOS) { location.href = 'bridge://' + cmd; } else if (WP) { // TODO ... } } var Bridge = { callByJS: function(opt) { log('callByJS', JSON.stringify(opt)); var input = {}; input.name = opt.name; input.token = ++guid; input.param = opt.param || {}; callbacks[input.token] = opt.callback; invoke(JSON.stringify(input)); }, callByNative: function(opt) { log('callByNative', JSON.stringify(opt)); var callback = callbacks[opt.token]; var ret = opt.ret || {}; var script = opt.script || ''; // Native主動調用Web if (script) { log('callByNative script', script); try { invoke(JSON.stringify({ token: opt.token, ret: eval(script) })); } catch (e) { console.error(e); } } // Web主動調用Native,Native被動響應 else if (callback) { callback(ret); try { delete callback; log(callbacks); } catch (e) { console.error(e); } } } }; window.Bridge = Bridge; window.__log = log; })(window);
目前一個Hybrid框架一般提供如下功能。
PhoneGap幾乎成了Hybrid的代名詞,Titanium和PhoneGap的設計理念差別較大,圖8-7形象地展現了PhoneGap和Titanium的組成部分。
圖8-7 Hybrid框架[11]
PhoneGap開發商Notibi 2010年將PhoneGap代碼貢獻給Apache軟件基金(ASF),PhoneGap核心引擎成爲新的開源項目Cordova,同時PhoneGap成了Cordova的一個發行版本[12]。2011年10月,Notibi被Adobe收購[13],但沒有影響到PhoneGap和Cordova的開源性質。
written once,run everywhere
如引文所述「一處編寫,多處運行」,PhoneGap主要的功能爲:
圖8-8 PhoneGap編譯打包功能
1.3 經典案例
來自PhoneGap Showcase[14]和其餘數據源的資料顯示:
Titanium設計思路和PhoneGap有很大不一樣,Titanium目的爲移動開發提供一種跨平臺的JavaScript運行時環境和API。
2.1 設計思路
Titanium設計的核心思路以下。
Titanium從設計理念上不追求「written once, run everywhere」,這是它的缺點,但同時它追求平臺差別的更佳的用戶體驗,於是也受到一部分用戶的追捧。Titanium的另外一個缺陷是插件難於擴展,要想支持新平臺則更加困難。
2.2 工做流程
工做流程以下。Titanium工做流如圖8-9所示。
圖8-9 Titanium工做流
書籍簡介
移動互聯網不可阻擋地進入了咱們的生活。做者將本身在百度和天貓期間的跨終端Web的開發實踐轉化爲書中的技術方案和實現,呈現給各位讀者。第1章提出了跨終端Web的概念以及實現跨終端Web的多重途徑,第2章主要介紹Mobile Web的技術基礎,第3~7章是全書的核心,按照開發流程組織逐步講解了實現跨終端Web所須要的各種技術基礎設施,第8章主要介紹了Hybrid App的發展歷程、實現細節以及成熟的框架,第9章介紹的跨終端存儲方案(Storage)是做者曾經的冠軍做品,第10章完整介紹瞭如何經過腳本錄製和回放來實現跨終端動做同步。
《跨終端 Web》講解深刻淺出,通暢易懂,適合有必定PC Web基礎,但願迅速瞭解Mobile Web,致力於PC和Mobile Web技術融合的讀者。
做者簡介
鬼道(原名徐凱),2011年畢業於同濟大學計算機系,模式識別方向碩士研究生。曾就任百度,現爲天貓前端通用組技術Leader。本書源於2013年7月在D2上的主題分享「移動優先的跨終端Web」,2013年11月在W3CTECH 2013作了第二次分享。