1. WKWebView
1.1 H5調Native(H5向Native傳遞消息)
1.1.1 H5調Native_直接攔截URL方式
顧名思義就是在WebView加載URL的時候,讀出URL字符串,看看里面有沒有你和H5特別約定的標記,如果有說明H5想向你傳遞消息,就干H5讓你干的事,忽略這個URL的定向跳轉。
攔截方法在下面回調:
webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
H5那邊的代碼:
就是重定向當前頁面URL。就是改變了location.href
的值。這里舉例子標記是bridge://doingSomething
,傳參{parma1=sss,parma2=dy}
h5AskNativeDoSomething1(){
location.href = "bridge://doingSomething&parma1=sss&parma2=dy"
}
Native代碼:
發現URL中包含bridge://doingSomething
,可以判斷H5要讓Native干事情,那么就decisionHandler(.cancel)
忽略這個URL的跳轉,取出對應參數干事情
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
let changeURLString:String = navigationAction.request.url?.absoluteString ?? "未知"
print("要跳轉的URL:\(changeURLString)")
/***方法1 攔截關鍵標識 bridge://doingSomething,根據自己和H5定了規則,去判斷取相應的參數 ***/
//方法1:js調用native
if changeURLString.contains("bridge://doingSomething"){
decisionHandler(.cancel)
let list:[String] = changeURLString.split(separator: "&").compactMap { "\($0)" }
print(list)
//TODO
}else{
decisionHandler(.allow)
}
}
1.1.2 H5調Native_WKScriptMessageHandler 回調方式
這是系統JavaScriptCore
提供的功能,用的時候需要引用類庫import JavaScriptCore
。
H5那邊代碼:
Native那邊通過WKScriptMessageHandler注冊的js對象暴露出來,這邊想向原生傳遞消息,固定寫法:window.webkit.messageHandlers.(JS對象XXXX字符串).postMessage({})
其中 window.webkit.messageHandlers 都是固定寫法,.postMessage({})也是固定寫法。這里例子完整寫法就是
window.webkit.messageHandlers.DIYJSBridge.postMessage({})
記住,如果沒有參數傳遞,({})小括號里面的大括號也不能省略,如果省略{},native那邊會無響應!如果有參數傳遞,那么{}里面就是鍵值對,如:{"param1":1,"param2":2}
/**
* native那邊通過WKScriptMessageHandler注冊的js對象暴露出來,這邊想向原生傳遞消息,固定寫法:window.webkit.messageHandlers.原生那邊暴露的js對象XXXX.postMessage({})
* 其中 window.webkit.messageHandlers 都是固定寫法,.postMessage({})也是固定寫法。記住,如果沒有參數傳遞,({})小括號里面的大括號也不能省略,如果省略{},native那邊會無響應
*/
h5AskNativeDoSomething2(){
window.webkit.messageHandlers.DIYJSBridge.postMessage({})
}
Navtive代碼:
我們在WKWebView初始化的時候,給它配置WKWebViewConfiguration
的里面添加一個類似監聽的東西:
let configuration:WKWebViewConfiguration = WKWebViewConfiguration()
//加監聽
let wkUserContnetController:WKUserContentController = WKUserContentController.init()
wkUserContnetController.add(self, name: "DIYJSBridge")//加監聽
configuration.userContentController = wkUserContnetController
webView = WKWebView.init(frame:self.view.bounds, configuration:configuration)
webView.scrollView.decelerationRate = UIScrollView.DecelerationRate.normal
webView.navigationDelegate = self
self.view.addSubview(webView)
wkUserContnetController.add(self, name: "DIYJSBridge")
這里給self
添加一個監聽,監聽到DIYJSBridge
這個JS對象發送的消息(先這么理解)。
然后實現WKScriptMessageHandler
協議的方法:
//MARK: - WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("方法2:\(message.name)")
print("方法2:\(message.body)")
}
這里面可以根據WKScriptMessage 讀到方法的名稱name和參數body,然后就可以干事情。
1.1.3 H5調Native_三方庫 WebViewJavascriptBridge
這個庫本質還是攔截URL,只是進行了封裝,讓方法定義和傳參更加對象化。具體源碼,有機會再寫篇文章解析一下!
H5那邊的代碼:
H5那邊需要在index.html定義一個方法,并調用。掛載對應的JS對象,完成相應的配置初始化。
//初始化方法
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe); }, 0);
}
//調用完成配置初始化
setupWebViewJavascriptBridge((bridge) => {});
現在H5想調用Native方法
h5AskNativeDoSomething3(){
this.toast("方法3:H5調用Native")
window.WebViewJavascriptBridge.callHandler('NativeToDingSomething',{"Pa1":"11111"}, function responseCallback(responseData) {
console.log(responseData)
})
}
window.WebViewJavascriptBridge.callHandler()
固定寫法,其中參數
第一個參數:Native那邊定義標記字符串,如:`NativeToDingSomething`
第二個參數:傳參,為{}括起來的鍵值對,如:`{"Pa1":"11111"}`
第三個參數:回調函數,如果Native那邊實現(下面Native實現了)了對應的回調Block,所帶的回調參數會在這個responseData里面
Native代碼:
Native這邊引入了三方庫WebViewJavascriptBridge,如后導入。
代碼初始化一個WebViewJavascriptBridge實例,并關聯上WebView
/**方法3 通過三方類庫**/
self.webViewBridge = WebViewJavascriptBridge.init(webView)
self.webViewBridge.setWebViewDelegate(self)
這時設置注冊一個標記NativeToDingSomething
,發現H5 callHandler
這個標記后干事情....
self.webViewBridge.registerHandler("NativeToDingSomething") { (ret:Any?, callBack:WVJBResponseCallback?) in
print(ret)
//TODO
if callBack != nil{
callBack!(["result":true,"data":["One","Two","Three"]])
}
}
這樣H5那邊如果觸發了
window.WebViewJavascriptBridge.callHandler('NativeToDingSomething',{"Pa1":"11111"}, function responseCallback(responseData) {
console.log("Native傳遞過來的參數:",responseData)
})
}
Native這邊收到消息會打印
Optional({
Pa1 = 11111;
})
同時Native這邊執行了回調callBack!(["result":true,"data":["One","Two","Three"]])
H5那邊的控制臺會打?。?/p>
這樣就完成了一次H5發起的雙向通信!
1.2 Native調H5(Native向H5傳遞消息)
1.2.1 Native調H5_直接WebView調用evaluateJavaScript方法
open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil)
如:
self.webView.evaluateJavaScript("nativeAskH5DoSomething('小孩')") { (any:Any?, err:Error?) in
if err == nil{
print("調用成功,返回結果\(any)")
}else{
print("調用失敗\(err)")
}
}
其中nativeAskH5DoSomething('小孩')
是H5定義的js方法
window.nativeAskH5DoSomething = function(mess){
console.log(mess)
return "我們都是好孩子"
}
注意:這種方法調用的js方法,必須掛載在Web的window對象上,不然會找不到!
evaluateJavaScript去調用h5中的方法之后,這個function要執行完成之后才會回調的app這邊,如果這個function中報錯了,回調到app這邊就會一直報錯。所以建議function中的東西可以先延遲執行。
1.2.2 Native調H5_通過 WebViewJavascriptBridge三方庫
這個H5調Native反過來相當于H5注冊一個標記,Native去調用。
H5代碼,注冊方法標識
window.WebViewJavascriptBridge.registerHandler("nativeAskH5DoSomething_WebViewJavascriptBridge",(data,callBack) => {
this.toast("原生調用我了")
console.log("原生調用我了")
console.log("傳入參數:",data)
callBack({"p1":1,"p2":90})
})
第一個參數data:表示原生傳入的參數
第二個參數callBack:是回調方法,執行后可穿參數給原生,告訴執行情況
Native代碼 事件觸發執行
self.webViewBridge.callHandler("nativeAskH5DoSomething_WebViewJavascriptBridge", data: "10086") { (ret:Any?) in
print("H5傳遞回來的參數結果:\(ret)")
}
執行結果:
H5打印結果
Native打印結果
H5傳遞回來的參數結果:Optional({
p1 = 1;
p2 = 90;
})
這樣也完成了一次Native發起的雙向通信!
2. UIWebView
H5調Native: 1.1.1,1.1.3 和WKWebView相同!
Native調H5: 1.2.1,1.2.2 和WKWebView相同,多了一種方式!
唯一的區別就是在1.1.2上,同時Native調H5多了使用JSContext方式
WKWebView用的是:WKScriptMessageHandler
UIWebView用的是:JSContext
因為現在都用WKWebView了,具體使用參照老鐵博客:http://www.lxweimin.com/p/88345985fe94