隨着H5功能愈發的強大,沒進行過混合開發的小夥們都很差意思說本身可以獨立進行iOS的app開發,在iOS7操做系統下,經常使用的native,js交互框架有easy-js,WebViewJavascriptBridge,以及結合javaScriptCore的框架。easy-js 很早的一個框架了,已經好幾年沒有人維護了,裏面有不少隱藏很深的坑,新人若是沒有用過的話,建議不要再用了。主要是js新建一個隱藏的iframe,經過攔截url的形式進行交互。WebViewJavascriptBridge是網上很火的一個交互庫,使用的人較多,可是對於js基礎較弱的小夥伴來講,底層不是太好理解。底層和easy-js同樣都是經過創新一個隱藏的iframe經過截取url來進行交互。缺點這裏就暫時不說了,用的很少,體會不夠深入。嘿嘿。javaScriptCore中JSExport進行交互,這種方式比較簡單易懂,也是我我的比較推崇 的一種方式。若是app最低版本操做系統是iOS7的小夥伴,建議本身搜一下相關知識點哦。可是WKWebView不可以利用javaScriptCore交互,是否是很坑爹哦,嗚嗚。
因爲本身去年的強力推進,今年咱們的一系列app最低操做系統都是從iOS8開始,因此今天重點和你們分享一下我是如何實現WKWebView與js交互的。
js發送消息給native的代理方法是:
方法1,javascript
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
主要是js方法消息調用native的方法。css
native調用js方法傳遞參數主要經過以下方法:
方法2html
[_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) { }];
相信這兩個方法你們在網上已經看到過不少遍了,貌似能夠解決與js交互的問題,實則否則,這兩個方法並無真正的幫咱們解決交互的問題。由於在js發送消息給native的時候,有時候須要經過回調來獲取相應的信息,僅僅靠上面兩個方法是沒有辦法知足的,也可能會有小夥伴說,先經過上面方法1發送消息個native而後,再使用方法2發送消息給js不就行了麼,不行的,這樣的話,js調用native方法時,和native發送消息時候並無時間前後的約定,不能保證,js獲取相關返回值的時候,必定能拿到值。
我一直在想如何能有一個與js調用native函數相關連的回調呢。功夫不負有心人,偶然看到H5 ,DOM能夠綁定事件,後來想能不能綁定自定義事件呢,一搜果真能夠,參考博客以下:
http://www.zhangxinxu.com/wordpress/2012/04/js-dom自定義事件/
順着這個思路,每一次js方法調用native方法的時候,我都爲這個js方法綁定一個對應的callBack方法,這樣的話,同時在發送的消息中告訴native須要回調,native方法就能夠執行完相關的方法後,直接回調相應的 callBack方法,並攜帶相關的參數,這樣就能夠完美的進行交互了。這裏我主要寫了一個JKEventHandler的js類,腳本內容以下:java
var JKEventHandler ={ callNativeFunction:function(functionString,params,callBack){ var methodName = (functionString.replace(/function\s?/mi,"").split("("))[0]; var callBackName =methodName + 'CallBack'; var message; if(!callBack){ message = {'methodName':methodName,'params':params}; window.webkit.messageHandlers.JKEventHandler.postMessage(message); }else{ message = {'methodName':methodName,'params':params,'callBackName':callBackName}; if(!Event._listeners[callBackName]){ Event.addEvent(callBackName, function(data){ callBack(data); }); } window.webkit.messageHandlers.JKEventHandler.postMessage(message); } }, callBack:function(callBackName,data){ Event.fireEvent(callBackName,data); }, removeAllCallBacks:function(data){ Event._listeners ={}; } }; var Event = { _listeners: {}, addEvent: function(type, fn) { if (typeof this._listeners[type] === "undefined") { this._listeners[type] = []; } if (typeof fn === "function") { this._listeners[type].push(fn); } return this; }, fireEvent: function(type,param) { var arrayEvent = this._listeners[type]; if (arrayEvent instanceof Array) { for (var i=0, length=arrayEvent.length; i<length; i+=1) { if (typeof arrayEvent[i] === "function") { arrayEvent[i](param); } } } return this; }, removeEvent: function(type, fn) { var arrayEvent = this._listeners[type]; if (typeof type === "string" && arrayEvent instanceof Array) { if (typeof fn === "function") { for (var i=0, length=arrayEvent.length; i<length; i+=1){ if (arrayEvent[i] === fn){ this._listeners[type].splice(i, 1); break; } } } else { delete this._listeners[type]; } } return this; } };
callNativeFunction:
這個函數主要是js調用native方法的時候進行調用的。若是有回調的話,須要在傳入的參數中寫出來哦。
callBack:
主要是用來觸發對應js方法回調函數的。ios
removeAllCallBacks:
主要是在要銷燬全部的callback事件時調用的。
以個人demo爲例git
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>iOS and Js</title> <style type="text/css"> * { font-size: 40px; } </style> </head> <body> <div style="margin-top: 100px"> <h1 style="color: red;">教你如何用H5與OC進行交互,而且把H5輸入的內容顯示到當前的控制器上</h1><br/> <div><input type="button" value="sendInfoToNative" onclick="sendInfoToNative()"></div> <br/> <div><input type="button" value="getInfoFromNative" onclick="getInfoFromNative()"></div> <br/> <div><input type="button" value="cleanAllCallBacks" onclick="cleanAllCallBacks()"></div> <br/> <div><input type="button" value="點擊觸發JS方法(callJsConfirm)" onclick="callJsConfirm()"></div><br/> </div> <br/> <div> <div><input type="button" value="點擊觸發JS輸入方法(callJsInput) " onclick="callJsInput()"></div><br/> </div> <br/> <div id="SwiftDiv"> <span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span> </div> <script type="text/javascript"> function sendInfoToNative() { var params ={'Phone':'13566668888'}; JKEventHandler.callNativeFunction(arguments.callee.toString(),params,null); } function getInfoFromNative(){ var params = {'Phone':'13933333333'}; JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){ alert(data); }); } function callJsConfirm() { if (confirm('confirm', 'Objective-C call js to show confirm')) { document.getElementById('jsParamFuncSpan').innerHTML = 'true'; } else { document.getElementById('jsParamFuncSpan').innerHTML = 'false'; } } function callJsInput() { var response = prompt('Hello', '請輸入你的名字:'); document.getElementById('jsParamFuncSpan').innerHTML = response; alert (response); } function cleanAllCallBacks(){ JKEventHandler.removeAllCallBacks(); } </script> </body> </html>
在js中調用getInfoFromNative
這個方法既能夠發送參數給native,同時也能夠從native獲取參數
具體實現:程序員
function getInfoFromNative(){ var params = {'Phone':'13933333333'}; JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){ alert(data); }); }
同時呢,經過JKEventHandler的轉換,在JKEventHandler+Demo.m文件中有一個同名的函數,只不過是參數不同:github
- (void)getInfoFromNative:(id)params :(void(^)(id response))callBack{ NSLog(@"params %@",params); NSString *str = @"'Hi Jack!'"; callBack(str); }
就這樣,我在native方法裏能夠獲取到js傳遞來的參數,同時經過callBack我也能夠傳遞參數給js。
另外呢在JKEventHandler文件裏,我寫了一個事件分發函數,主要就是爲了解決多個js方法交互的問題。感興趣的小夥伴能夠看看個人demo哦。
另外須要你們注意的是,WKWebView所在的ViewController即將被銷燬的時候,也就是WKWebView即將被銷燬的時候,必定要記得調用以下方法銷燬全部的callback事件哦:web
[_webView evaluateJavaScript:@"JKEventHandler.removeAllCallBacks();" completionHandler:^(id _Nullable data, NSError * _Nullable error) { }];//刪除全部的回調事件
俗話說的話,代碼就是程序員最好的老師,這裏我就很少說了,Demo地址
如何使用了cocoapod,能夠:app
pod "JKWKWebViewHandler"