本文原創:wangtiegangjavascript
Hybrid App,俗稱混合應用,即混合了 Native技術 與 Web技術 進行開發的移動應用。兼具" Native App良好用戶交互體驗的優點 "和" Web App跨平臺開發的優點 "。html
Hybrid APP底層依賴於Native提供的容器(UIWebview),上層使用Html&Css&JS作業務開發,底層透明化、上層多多樣化,這種場景很是有利於前端介入,很是適合業務快速迭代。前端
Hybrid App,俗稱混合應用,即混合了 Native技術 與 Web技術 進行開發的移動應用。如今比較流行的混合方案主要有三種,主要是在UI渲染機制上的不一樣:java
經過JSBridge,H5頁面能夠調用Native的api,Native也可調用H5頁面的方法或者通知H5頁面回調,從而實現雙向通訊,以下圖 android
基於 WebView 的機制和開放的 API, 實現這個功能有三種常見的方案:web
class JsObject { @JavascriptInterface public String toString() { return "injectedObject"; } } webview.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new JsObject(), "injectedObject"); webView.loadData("", "text/html", null); webView.loadUrl("javascript:alert(injectedObject.toString())"); 複製代碼
可是此方法使用須要注意:json
WebView 中的 prompt/console/alert 攔截,一般使用 prompt,由於這個方法在前端中使用頻率低,比較不會出現衝突;api
WebView URL Scheme 跳轉攔截;瀏覽器
第二三種機制的原理是相似的,都是經過對 WebView 信息冒泡傳遞的攔截,從而達到通信的,目前多使用後兩種方法。緩存
實現過程以下:
經過特定的參數轉換方法,將傳入的數據,方法名一塊兒,拼接成一個url scheme,如
// 基本有用信息就是後面的callbackId,handlerName與data API_Name:callbackId/handlerName?param0=xxx¶m1=yyy 複製代碼
經過上面的定義來對應Native層不一樣的方法,並傳遞參數
咱們會使用建立 iframe 發送請求的方式。如
//建立隱藏iframe過程 var messagingIframe = document.createElement('iframe'); messagingIframe.style.display = 'none'; document.documentElement.appendChild(messagingIframe); //觸發scheme messagingIframe.src = uri; 複製代碼
onJsAlert()
,onJsConfirm()
,onJsPrompt()
,方法回調攔截對話框消息var data = { action:'xxxx', params:'xxxx', callback:'xxxx', }; var jsonData = JSON.stringify([data]); //發起彈框 window.prompt(jsonData); 複製代碼
一般考慮到安全性,須要在客戶端中設置域名白名單或者限制,避免公司內部業務協議被第三方直接調用。
對應上面消息的發送,消息的攔截方法以下:
客戶端能夠經過 API 對 WebView 發出的請求進行攔截:
IOS上: shouldStartLoadWithRequest
Android: shouldOverrideUrlLoading
當解析到請求 URL 頭爲制定的協議時,便不發起對應的資源請求,而是 解析參數,並進行相關功能或者方法的調用,完成協議功能的映射。
以onJsPrompt爲例,客戶端能夠經過 API 對 WebView 發出的請求進行攔截:
IOS上: runJavaScriptTextInputPanelWithPrompt
Android: WebChromeClient.onJsPrompt
處理方式同上
因爲 WebView 對 URL 會有長度的限制,所以常規的經過 scheme參數 進行傳遞的方式便具備一個問題,即當須要傳遞的參數過長時,可能會致使被截斷,例如傳遞base64或者傳遞大量數據時。因爲 Native 能夠直接調用 JS 方法並直接獲取函數的返回值,所以咱們只須要對每條協議標記一個惟一標識,並把參數存入參數池中,到時客戶端再經過該惟一標識從參數池中獲取對應的參數便可。
當消息發送到Native 層後,咱們便須要處理對應的回調,一樣須要的處理過程:
因爲 Native 能夠算做 H5 的宿主,所以擁有更大的權限,上面也提到了 Native 能夠經過 WebView API直接執行 Js 代碼。
// IOS webview.stringByEvaluatingJavaScriptFromString("alert('NativeCall')") // Android 4.4- webView.loadUrl("javascript:JSBridge.trigger('NativeCall')") // Android 4.4+ mWebView.evaluateJavascript("javascript:JSBridge.trigger('NativeCall')", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此處爲 js 返回的結果 } }); 複製代碼
android系統在低於4.4時,evaluateJavascript 是沒法使用的,所以單純的使用 loadUrl 沒法獲取 JS 返回值,這時咱們須要使用前面提到的 prompt 的方法進行兼容,讓 H5端 經過 prompt 進行數據的發送,客戶端進行攔截並獲取相應數據
在線獲取h5資源總會遇到網絡問題,對於一些不會常常改變的資源放到本地緩存,能夠提升訪問速度和穩定性。
一般來講,H5資源分爲兩種,常常更新的業務代碼 和 不常常更新的框架、庫代碼和公用組件代碼,爲了實現離線資源的共享,在H5打包時能夠採用分包的策略,將公用部分單獨打包,在本地也是單獨存放
爲了實現同一資源的線上和離線訪問, Native 層須要對 H5 請求的資源進行判斷,究竟是從線上獲取仍是本地獲取,這裏咱們暫時稱之爲 LocalUrlRouter。
接下來就是如何獲取離線資源了,咱們上面提到了 LocalUrlRouter,它負責線上資源到本地資源映射,咱們借鑑已有的映射規則:H5開發完成後會掃描H5項目而後生成一份線上資源和本地資源路徑的映射表(source-router.json)。每次請求資源時,LocalUrlRouter 會檢查映射表,若是本地有離線資源,則會返回本地資源,不然經過http請求獲取線上資源。
還能夠完善的地方資源包的更新,映射表對資源的緩存也能夠動態的增長等