javascript
UIWebView中JS与OC交互 WebViewJavascriptBridge的使用
一、綜述
現(xiàn)在很多的應(yīng)用都會(huì)在多種平臺(tái)上發(fā)布,所以很多程序猿們都開(kāi)始使用Hybrid App的設(shè)計(jì)模式。就是在app上嵌入網(wǎng)頁(yè),只要寫一份網(wǎng)頁(yè)代碼,就可以跑在不同的系統(tǒng)上。在iOS中,app多是通過(guò)WebView來(lái)加載網(wǎng)頁(yè),由于功能需求等原因,代碼中少不得要和跟網(wǎng)頁(yè)交互。
二、原理
在iOS中,本地調(diào)用Javascript語(yǔ)言,是通過(guò)UIWebView中的實(shí)例方法stringByEvaluatingJavaScriptFromString:來(lái)實(shí)現(xiàn)的,該方法通過(guò)字符串對(duì)象的形式傳入JS代碼。
| 1 | [webView stringByEvaluatingJavaScriptFromString:@"Math.random();"]; |
? 而JS調(diào)用本地的代碼,則并沒(méi)有現(xiàn)成的API,而是需要間接地通過(guò)一些方法來(lái)實(shí)現(xiàn)。我們利用UIWebView的代理方法,當(dāng)UIWebView發(fā)起的所有網(wǎng)絡(luò)請(qǐng)求,都可以通過(guò)delegate函數(shù)在Native層得到通知。這樣,我們就可以在UIWebView內(nèi)發(fā)起一個(gè)自定義的網(wǎng)絡(luò)請(qǐng)求,比如:'wvjbscheme://__BRIDGE_LOADED__'。于是在UIWebView的delegate函數(shù)中,我們攔截url,只要發(fā)現(xiàn)是我們自定義的url,就不進(jìn)行內(nèi)容的加載,轉(zhuǎn)而執(zhí)行相應(yīng)的調(diào)用邏輯。
三、WebViewJavascriptBridge的使用
1、WebViewJavascriptBridge簡(jiǎn)介
WebViewJavascriptBridge支持到iOS6之前的版本的,用于支持native的iOS與javascript交互,接下來(lái)講講WebViewJavascriptBridge的基本原理及應(yīng)該如何去使用,包括iOS端的使用和JS端的使用。
首先,看看WebViewJavascriptBridge.m中Webview代理攔截的代碼:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary?*)actionInformation request:(NSURLRequest?*)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener { ????if?(webView != _webView) {?return; } ????? ????NSURL?*url = [request URL]; ????if?([_base isCorrectProcotocolScheme:url]) { ????????if?([_base isBridgeLoadedURL:url]) { ????????????[_base injectJavascriptFile]; ????????}?else?if?([_base isQueueMessageURL:url]) { ????????????NSString?*messageQueueString = [self?_evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; ????????????[_base flushMessageQueue:messageQueueString]; ????????}?else?{ ????????????[_base logUnkownMessage:url]; ????????} ????????[listener ignore]; ????}?else?if?(_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { ????????[_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; ????}?else?{ ????????[listener use]; ????} } |
? WebViewJavascriptBridge是通過(guò)webview的代理攔截scheme,然后注入相應(yīng)的JS,在攔截后,通過(guò)先通過(guò)-isBridgeLoadedURL:方法判斷URL是否是需要bridge的URL,若是,則通過(guò)injectJavascriptFile方法注入JS;否則判斷URL是否是隊(duì)列消息,若是,則執(zhí)行查詢命令JS并刷新消息隊(duì)列;如果都不匹配,URL被識(shí)別為未知的消息。
?
2、WebViewJavascriptBridge的使用
首先,要在JS中接入這個(gè)框架,這段代碼是不變的
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | /** ?*? 此為js接入框架的函數(shù) ?*/ 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 =?'wvjbscheme://__BRIDGE_LOADED__'; ????document.documentElement.appendChild(WVJBIframe); ????setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0) } |
?
然后OC要調(diào)用到的JS函數(shù)要在下面函數(shù)中使用bridge.registerHandler來(lái)注冊(cè),而且JS需要調(diào)用的OC方法也要在下面的函數(shù)中用bridge.callHandler調(diào)用
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /** ?*? OC調(diào)用的JS函數(shù)需在此處注冊(cè),調(diào)用OC方法也需要在此處調(diào)用 ?*/ ????setupWebViewJavascriptBridge(function(bridge) { ????????var uniqueId = 1 ????????function log(message, data) { ????????????var log = document.getElementById('log') ????????????var el = document.createElement('div') ????????????el.className =?'logLine' ????????????el.innerHTML = uniqueId++ +?'. '?+ message +?':<br/>'?+ JSON.stringify(data) ????????????if?(log.children.length) { log.insertBefore(el, log.children[0]) } ????????????else?{ log.appendChild(el) } ????????} ?????????????????????????????????? ????????//注冊(cè)一個(gè)給OC調(diào)用的函數(shù),不帶參數(shù) ????????bridge.registerHandler('WebViewDidLoad',function() { ????????????log("WebViewDidLoad") ????????}) ????????? ????????//注冊(cè)一一個(gè)給OC調(diào)用的函數(shù),接受OC傳來(lái)的一個(gè)參數(shù)和一個(gè)回調(diào)處理 ????????bridge.registerHandler('OC_Call_JS', function(data, responseCallback) { ????????????log('oc調(diào)用js -', data) ????????????var responseData = {?'Javascript response':'oc調(diào)用JS成功!'?} ????????????log('js被調(diào)用后響應(yīng)-', responseData) ????????????responseCallback(responseData) ????????}) ????????document.body.appendChild(document.createElement('br')) ????????var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button')) ????????callbackButton.innerHTML =?'JS_Call_ObjC' ????????callbackButton.onclick = function(e) { ????????????e.preventDefault() ????????????log('JS call OC') ????????????//此處調(diào)用OC方法 ????????????bridge.callHandler('JS_Call_ObjC', {'foo':?'bar'}, function(response) { ????????????????log('JS call OC sucess and get OC rsp', response) ????????????}) ????????} ????}) |
需要注意的是:在setupWebViewJavascriptBridge(function(bridge) {}函數(shù)體內(nèi)的代碼不能有錯(cuò)誤,不然會(huì)導(dǎo)致不任何回調(diào),不打印日志(JS的是腳本語(yǔ)言,跑到錯(cuò)的地方就不跑了)。
?
OC部分,首先打開(kāi)框架的日志系統(tǒng),然后關(guān)聯(lián)webView
| 1 2 3 | [WebViewJavascriptBridge enableLogging]; ????? ????_bridge = [WebViewJavascriptBridge bridgeForWebView:webView]; |
? JS需要調(diào)用的OC方法,要在OC代碼中注冊(cè)
| 1 2 3 4 | [_bridge registerHandler:@"JS_Call_ObjC"?handler:^(id?data, WVJBResponseCallback responseCallback) { ????????NSLog(@"JS調(diào)用OC: %@", data); ????????responseCallback(@"OC被調(diào)用后響應(yīng):調(diào)用成功!"); ????}]; |
? 而想要調(diào)用JS中注冊(cè)過(guò)的函數(shù),在需要的地方用實(shí)例方法callHandler調(diào)用就可以了
| 1 2 3 4 | id?data = @{ @"OC調(diào)用JS": @"Hi there, JS!"?}; [_bridge callHandler:@"OC_Call_JS"?data:data responseCallback:^(id?response) { ????NSLog(@"testJavascriptHandler responded: %@", response); }]; |
?
四、小結(jié)
最近因?yàn)轫?xiàng)目需要,正在邊學(xué)邊做Hybrid App,剛好用到這個(gè)第三方,就寫了篇文分享出來(lái),希望能幫到剛剛?cè)胧值娜?#xff0c;以上實(shí)例的demo地址https://github.com/GarenChen/WebViewJSBridgeDemo喜歡的順手給個(gè)star ^_^;
推薦一些閱讀:
JSBridge——Web與Native交互之iOS篇:http://www.jianshu.com/p/9fd80b785de1
Hybrid App 開(kāi)發(fā)模式:http://www.tuicool.com/articles/riE3Yn
WebViewJavascriptBridge:https://github.com/marcuswestin/WebViewJavascriptBridge
總結(jié)
以上是生活随笔為你收集整理的UIWebView中JS与OC交互 WebViewJavascriptBridge的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: gatekeeper学习概述
- 下一篇: Entity Framework中的Mi