IOS、Android與H5通信-JsBridge原理(總結)
H5和原生app(ios,android)交互的載體基本都是基於Webview,可以把Webview看作是一個性能打八折的移動瀏覽器。
ios調用Javascript
簡單說下這幾種:WKWebView 、UIWebView、JavaScriptCore
WKWebView:蘋果在ios8之后也引入了專門負責處理網頁視圖的框架WebKit,Webkit是啥,接觸過H5、chrome的肯定都知道。chrome使用的也是基於webkit內核的Chromium引擎。WKWebView優點很多,支持更多H5特性,刷新效率及內置手勢等,更加強大,性能也更優,不一一列舉,如果大家app不需要兼容7及以下版本,不需要攔截一些請求,直接解析本地一些文件,建議使用WKWebView。
UIWebView:較老webview,第一代。其中stringByEvaluatingJavaScriptFromString方法提供了OC與js交互的能力。
JavaScriptCore(ios7及以后版本)。JavaScriptCore框架是webkit重要組成部分,主要是對JS進行解析和提供執行環境,Javascript的虛擬機,有點類似v8引擎,我自己這么理解:)正是它為ios提供了執行JavaScript代碼的能力。ReactNative應該都是通過JavaScriptCore去解析的(自己猜測)。
微信小程序的邏輯層也是由JavaScriptCore作為運行環境。
Javascript 調用 ios(oc、swift)原理:
目前兼顧兼容性、比較成熟的方案還是通過攔截URL的方式。
UIWebView的特性,在UIWebView內發起的所有網絡請求,都可以在Native層被捕捉到。
利用這一特性,就可以在UIWebView內發起一個自定義的網絡請求,一般格式:jsbridge://method?參數1=value1&參數2=value2
於是在UIWebView中,只要發現是jsbridge://開頭的url,就不進行內容的加載,而是執行相應的邏輯處理。
嵌入webview的h5中的js一般是通過動態創建隱藏iframe標簽,賦值上文提到的鏈接給src,iframe不會引起頁面調轉、刷新。
主要代碼:
var src= 'jsbridge://method?參數1=value1&參數2=value2';
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = src;
document.body.appendChild(iframe);
//再刪除
iframesetTimeout(function() {
iframe.remove();
}, 50);
Android和Javascript互相調用
Android WebView也是基於WebKit引擎的一個組件,Android的Webview在低版本和高版本采用了不同的webkit版本內核,4.4后直接使用了Chrome。
這個組件功能非常強大,除了具有一般View的屬性和設置外,還可以對url請求、頁面加載、渲染、頁面交互進行強大的處理。
Android調用JS代碼的方法主要有2種:
1、WebView的loadUrl
2、WebView的evaluateJavascript
JS調用Android代碼的方法主要有3種:
1、WebView的addJavascriptInterface進行對象映射(低版本Android4以下好像有一些安全問題,本人沒有驗證)
2、WebViewClient 的 shouldOverrideUrlLoading 方法回調攔截 url
3、WebChromeClient 的onJsAlert、onJsConfirm、onJsPrompt方法回調攔截JS對話框alert()、confirm()、prompt() 消息
一般常用onJsPrompt、prompt進行回調攔截
JSBridge是Native代碼與JS代碼的通信橋梁
設計一個jsbridge主要分幾大步驟:
第一步:設計出一個Native與JS交互的全局中間對象
第二步:JS如何調用Native
第三步:Native如何得知api被調用
第四步:分析url-參數和回調的格式
第五步:Native如何調用JS
第六步:H5中api方法的注冊以及格式
結合場景運用:
運用場景描述:在H5端點擊頁面的發送按鈕通知APP打開微信分享功能,交互寫在發送事件函數中,調起微信分享功能由app端操作
//給到app的json參數 let jsonData = { reload: this.$route.query.no_reload ? false : true, //true需要重新加載返回列表頁,false不需要(根據需求定) title: '上門試駕邀請', // 分享標題 desc: '邀請您試駕體驗xxxx', // 分享描述 link: 'https://xxxxx', // 分享鏈接 imgUrl: '', // 分享圖標 }
判斷設備
device() { let u = window.navigator.userAgent; //android終端 let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //ios終端 let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); return {android: isAndroid, ios: isiOS} },
JS與IOS交互方式一:WKScriptMessageHandler
WKWebView有一個內容交互控制器,該對象提供了通過JS向WKWebView發送消息的途徑。需要設置MessageHandler,大家把這個功能簡稱為MessageHandler。
IOS具體實現參考:鏈接
這里只說js調用
/ window.webkit.messageHandlers.<name>.postMessage(<messageBody>) // 這個name就是設置MessageHandler的第一個參數,與IOS約定的方法名 // messageBody 必須是json格式,為空時傳null window.webkit.messageHandlers.ShareContract.postMessage(jsonData);
JS與IOS交互方式二:WebViewJavascriptBridge交互 攔截url做事件處理,如果要傳參數,不建議用這種
//模擬 h5頁面在app端的跳轉 let data = '{"type": "basisTongji", "url":"' + "https://xxxx/basisTongji.html" + "}"; window.WebViewJavascriptBridge.javaScrpitRresponseJson(data);
Android端交互
冒號前面區分是什么功能,冒號后面是接收的參數
window.location.href = "ShareContract:" + JSON.stringify(jsonData);
運用場景二:登錄失效的情況下,通知APP端,需要跳轉到登錄頁面
- exit:true是和安卓約定的功能名及參數
- logout 是和IOS約定的方法名,注意當值為空的時候,需要傳null,不能什么都不寫,不然會走代理。。。
let deviceP = device() if (deviceP.android) { window.location.href = "exit:true" } if (deviceP.ios) { //ios 交互 window.webkit.messageHandlers.logout.postMessage(null); }