現在市面上App,迭代變更比較頻繁,為了滿足業務需求,基本上都采用了Hybrid混編,來實作業務的快速上下線,H5靈活開發的特點和線上熱更新的機制是非常適合業務頻繁迭代的,我們需要一套完整的Hybrid技術架構方案來充分利用 H5 強大的開發和迭代能力,又能賦予 H5 強大的底層能力和用戶體驗,同時能復用現有的成熟 Native組件,
Hybrid技術原理
Hybrid 最核心的點就是如何處理 Native端 與 H5端 之間的雙向通訊層,其實這里也可以理解為我們需要一套跨語言通訊方案,來完成 Native(Java/Objective-c/…) 與 JavaScript 的通訊,也就是我們所說的 JSBridge,Hybrid App 實作的關鍵就是作為容器的Webview,使用WebView 作為容器直接承載 Web頁面,
Web容器是連接Native和H5的紐帶,這里又分為JavaScript 給Native發通知和Native通知JavaScript,
JavaScript 通知Native
- API注入,原理其實就是 Native 獲取 JavaScript環境背景關系,并直接在上面掛載物件或者方法,使 js 可以直接呼叫,Android 與 IOS 分別擁有對應的掛載方式,
- WebView 中的 prompt/console/alert 攔截,通常使用 prompt,因為這個方法在前端中使用頻率低,比較不會出現沖突;
- WebView URL Scheme 跳轉攔截
第二三種機制的原理是類似的,都是通過對 WebView 資訊傳遞的攔截,從而達到通訊的,接下來我們主要從 原理-定制協議-攔截協議-引數傳遞-回呼機制 5個方面詳細闡述下第三種方案 – URL攔截方案,
實作原理
在 WebView 中發出的網路請求,客戶端都能進行監聽和捕獲
協議的定制
我們需要制定一套URL Scheme規則,通常我們的請求會帶有對應的協議開頭,例如常見的 https://xxx.com 或者 file://1.jpg,代表著不同的含義,我們這里可以將協議型別的請求定制為:
xxcommand://xxxx?param1=1¶m2=2
這里有幾個需要注意點的是:
(1) xxcommand:// 只是一種規則,可以根據業務進行制定,使其具有含義,例如我們定義 xxcommand:// 為公司所有App系通用,為通用工具協議:
xxcommand://getProxy?h=1
而定義 xxapp:// 為每個App單獨的業務協議,
xxapp://openCamera?h=2
不同的協議頭代表著不同的含義,這樣便能清楚知道每個協議的適用范圍,
(2) 這里不要使用 location.href 發送,因為其自身機制有個問題是同時并發多次請求會被合并成為一次,導致協議被忽略,而并發協議其實是非常常見的功能,我們會使用創建 iframe 發送請求的方式,
(3) 通常考慮到安全性,需要在客戶端中設定域名白名單或者限制,避免公司內部業務協議被第三方直接呼叫,
協議的攔截
客戶端可以通過 API 對 WebView 發出的請求進行攔截:
IOS上: shouldStartLoadWithRequest
Android: shouldOverrideUrlLoading
當決議到請求 URL 頭為制定的協議時,便不發起對應的資源請求,而是決議引數,并進行相關功能或者方法的呼叫,完成協議功能的映射,
協議回呼
由于協議的本質其實是發送請求,這屬于一個異步的程序,因此我們便需要處理對應的回呼機制,這里我們采用的方式是JS的事件系統,這里我們會用到 window.addEventListener 和 window.dispatchEvent這兩個基礎API;
發送協議時,通過協議的唯一標識注冊自定義事件,并將回呼系結到對應的事件上,
客戶端完成對應的功能后,呼叫 Bridge 的dispatch API,直接攜帶 data 觸發該協議的自定義事件,
通過事件的機制,會讓開發更符合我們前端的習慣,例如當你需要監聽客戶端的通知時,同樣只需要在通過 addEventListener 進行監聽即可,
Tips: 這里有一點需要注意的是,應該避免事件的多次重復系結,因此當唯一標識重置時,需要removeEventListener對應的事件,
引數傳遞方式
由于 WebView 對 URL 會有長度的限制,因此常規的通過 search引數 進行傳遞的方式便具有一個問題,既 當需要傳遞的引數過長時,可能會導致被截斷,例如傳遞base64或者傳遞大量資料時,
因此我們需要制定新的引數傳遞規則,我們使用的是函式呼叫的方式,這里的原理主要是基于:
Native 可以直接呼叫 JS 方法并直接獲取函式的回傳值,
我們只需要對每條協議標記一個唯一標識,并把引數存入引數池中,到時客戶端再通過該唯一標識從引數池中獲取對應的引數即可,
Native 通知 Javascript
由于 Native 可以算作 H5 的宿主,因此擁有更大的權限,上面也提到了 Native 可以通過 WebView API直接執行 Js 代碼,這樣的權限也就讓這個方向的通訊變得十分的便捷,
IOS: stringByEvaluatingJavaScriptFromString
// Swift
webview.stringByEvaluatingJavaScriptFromString("alert('NativeCall')")
Android: loadUrl (4.4-)
// 呼叫js中的JSBridge.trigger方法
// 該方法的弊端是無法獲取函式回傳值;
webView.loadUrl("javascript:JSBridge.trigger('NativeCall')")
Tips: 當系統低于4.4時,evaluateJavascript 是無法使用的,因此單純的使用 loadUrl 無法獲取 JS 回傳值,這時我們需要使用前面提到的 prompt 的方法進行兼容,讓 H5端 通過 prompt 進行資料的發送,客戶端進行攔截并獲取資料,
Android: evaluateJavascript (4.4+)
// 4.4+后使用該方法便可呼叫并獲取函式回傳值;
mWebView.evaluateJavascript("javascript:JSBridge.trigger('NativeCall')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處為 js 回傳的結果
}
});
基于上面的原理,我們已經明白 JSBridge 最基礎的原理,并且能實作 Native <=> H5 的雙向通訊機制了,

JSBridge 的接入
接下來,我們來理下代碼上需要的資源,實作這套方案,從上圖可以看出,其實可以分為兩個部分:
JS部分(bridge): 在JS環境中注入 bridge 的實作代碼,包含了協議的拼裝/發送/引數池/回呼池等一些基礎功能,
Native部分(SDK):在客戶端中 bridge 的功能映射代碼,實作了URL攔截與決議/環境資訊的注入/通用功能映射等功能,
我們這里的做法是,將這兩部分一起封裝成一個 Native SDK,由客戶端統一引入,客戶端在初始化一個 WebView 打開頁面時,如果頁面地址在白名單中,會直接在 HTML 的頭部注入對應的 bridge.js,這樣的做法有以下的好處:
雙方的代碼統一維護,避免出現版本分裂的情況,有更新時,只要由客戶端更新SDK即可,不會出現版本兼容的問題;
App的接入十分方便,只需要按檔案接入最新版本的SDK,即可直接運行整套Hybrid方案,便于在多個App中快速的落地;
H5端無需關注,這樣有利于將 bridge 開放給第三方頁面使用,
這里有一點需要注意的是,協議的呼叫,一定是需要確保執行在bridge.js 成功注入后,由于客戶端的注入行為屬于一個附加的異步行為,從H5方很難去捕捉準確的完成時機,因此這里需要通過客戶端監聽頁面完成后,基于上面的回呼機制通知 H5端,頁面中即可通過window.addEventListener(‘bridgeReady’, e => {})進行初始化,
App中 H5 的接入方式
將 H5 接入 App 中通常有兩種方式:
(1) 在線H5,這是最常見的一種方式,我們只需要將H5代碼部署到服務器上,只要把對應的 URL地址 給到客戶端,用 WebView 打開該URL,即可嵌入,該方式的好處在于:
獨立性強,有非常獨立的開發/除錯/更新/上線能力;資源放在服務器上,完全不會影響客戶端的包體積;接入成本很低,完全的熱更新機制,
但相對的,這種方式也有對應的缺點:
完全的網路依賴,在離線的情況下無法打開頁面;
首屏加載速度依賴于網路,網路較慢時,首屏加載也較慢;
通常,這種方式更適用在一些比較輕量級的頁面上,例如一些幫助頁、提示頁、使用攻略等頁面,這些頁面的特點是功能性不強,不太需要復雜的功能協議,且不需要離線使用,在一些第三方頁面接入上,也會使用這種方式,例如我們的頁面呼叫微信JS-SDK,
(2) 內置包H5,這是一種本地化的嵌入方式,我們需要將代碼進行打包后下發到客戶端,并由客戶端直接解壓到本地儲存中,通常我們運用在一些比較大和比較重要的模塊上,
其優點是:
由于其本地化,首屏加載速度快,用戶體驗更為接近原生;可以不依賴網路,離線運行;
但同時,它的劣勢也十分明顯:
開發流程/更新機制復雜化,需要客戶端,甚至服務端的共同協作;會相應的增加 App 包體積;
這兩種接入方式均有自己的優缺點,應該根據不同場景進行選擇,
參考自:https://segmentfault.com/a/1190000015678155
Android:WebView與Javascript互動(相互呼叫引數、傳值)
| 如果你也熱衷技識訓迎加群一起進步:230274309 , 一起分享,一起進步!少劃水,多曬干貨!!歡迎大家!!!(進群潛水者勿加) |
點擊鏈接加入群聊【編程之美】:https://jq.qq.com/?_wv=1027&k=h75BfFCg
或者掃碼

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256323.html
標籤:AI
下一篇:Linux系統安全與應用(二)——安全機制、安全控制、弱口令檢測JR、網路掃描NMAP和控制臺命令Netstat
