優秀開源代碼解讀之JS與iOS Native Code互調的優雅實現方案

簡介

本篇爲你們介紹一個優秀的開源小項目:WebViewJavascriptBridgejavascript

它優雅地實現了在使用UIWebView時JS與ios 的ObjC nativecode之間的互調,支持消息發送、接收、消息處理器的註冊與調用以及設置消息處理的回調。前端

就像項目的名稱同樣,它是鏈接UIWebView和Javascript的bridge。在加入這個項目以後,他們之間的交互處理方式變得很友好。java

在native code中跟UIWebView中的js交互的時候,像下面這樣:ios

 

  1. //發送一條消息給UI端並定義回調處理邏輯  
  2.  [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id error, id responseData) {  
  3.         if (error) { NSLog(@"Uh oh - I got an error: %@", error); }  
  4.         NSLog(@"objc got response! %@ %@", error, responseData);  
  5.  }];  
//發送一條消息給UI端並定義回調處理邏輯
 [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id error, id responseData) {
        if (error) { NSLog(@"Uh oh - I got an error: %@", error); }
        NSLog(@"objc got response! %@ %@", error, responseData);
 }];

 

 

而在UIWebView中的js跟native code交互的時候也變得很簡潔,好比在調用處理器的時候,就能夠定義回調處理邏輯:git

[javascript] view plain copy print ?
  1. //調用名爲testObjcCallback的native端處理器,並傳遞參數,同時設置回調處理邏輯  
  2. bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {  
  3. <span style="white-space: pre;">    </span>log('Got response from testObjcCallback', response)  
  4. })  
//調用名爲testObjcCallback的native端處理器,並傳遞參數,同時設置回調處理邏輯
bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
	log('Got response from testObjcCallback', response)
})

一塊兒來看看它的實現吧,它總共就包含了三個文件:github

 

  1. WebViewJavascriptBridge.h  
  2. WebViewJavascriptBridge.m  
  3. WebViewJavascriptBridge.js.txt  
WebViewJavascriptBridge.h
WebViewJavascriptBridge.m
WebViewJavascriptBridge.js.txt

 

它們是以以下的模式進行交互的:web

很明顯:WebViewJavascriptBridge.js.txt主要用於銜接UIWebView中的web page,而WebViewJavascriptBridge.h/m則主要用於與ObjC的native code打交道。他們做爲一個總體,其實起到了一個「橋樑」的做用,這三個文件封裝了他們具體的交互處理方式,只開放出一些對外的涉及到業務處理的API,所以你在須要UIWebView與Native code交互的時候,引入該庫,則無需考慮太多的交互上的問題。整個的Bridge對你來講都是透明的,你感受編程的時候,就像是web編程的前端和後端同樣清晰。編程

 

簡單地羅列一下它能夠實現哪些功能吧:後端

出於表達上的須要,對於UIWebView相關的我就稱之爲UI端,而objc那端的處理代碼稱之爲Native端。app

【1】UI端

(1)   UI端在初始化時支持設置消息的默認處理器(這裏的消息指的是從Native端接收到的消息)

(2)   從UI端向Native端發送消息,並支持對於Native端響應後的回調處理的定義

(3)   UI端調用Native定義的處理器,並支持Native端響應後的回調處理定義

(4)   UI端註冊處理器(供Native端調用),並支持給Native端響應處理邏輯的定義

【2】 Native端

(1)   Native端在初始化時支持設置消息的默認處理器(這裏的消息指的是從UI端發送過來的消息)

(2)   從Native端向UI端發送消息,並支持對於UI端響應後的回調處理邏輯的定義

(3)   Native端調用UI端定義的處理器,並支持UI端給出響應後在Native端的回調處理邏輯的定義

(4)   Native端註冊處理器(供UI端調用),並支持給UI端響應處理邏輯的定義

 

UI端以及Native端徹底是對等的兩端,實現也是對等的。一段是消息的發送端,另外一段就是接收端。這裏爲引發混淆,須要解釋一下我這裏使用的「響應」、「回調」在這個上下文中的定義:

(1)   響應:接收端給予發送端的應答

(2)   回調:發送端收到接收端的應答以後在接收端調用的處理邏輯

下面來分析一下源碼:

WebViewJavascriptBridge.js.txt:

主要完成了以下工做:

(1) 建立了一個用於發送消息的iFrame(經過建立一個隱藏的ifrmae,並設置它的URL 來發出一個請求,從而觸發UIWebView的shouldStartLoadWithRequest回調協議)

(2) 建立了一個核心對象WebViewJavascriptBridge,並給它定義了幾個方法,這些方法大部分是公開的API方法

(3) 建立了一個事件:WebViewJavascriptBridgeReady,並dispatch(觸發)了它。

代碼解讀

UI端實現

對於(1),相應的代碼以下:

[javascript] view plain copy print ?
  1. /* 
  2.  *建立一個iFrame,設置隱藏並加入到DOM中 
  3.  */  
  4.     function _createQueueReadyIframe(doc) {  
  5.         messagingIframe = doc.createElement('iframe')  
  6.         messagingIframe.style.display = 'none'  
  7.         doc.documentElement.appendChild(messagingIframe)  
  8.     }  
/*
 *建立一個iFrame,設置隱藏並加入到DOM中
 */
	function _createQueueReadyIframe(doc) {
		messagingIframe = doc.createElement('iframe')
		messagingIframe.style.display = 'none'
		doc.documentElement.appendChild(messagingIframe)
	}

對於(2)中的WebViewJavascriptBridge,其對象擁有以下方法:

  1. window.WebViewJavascriptBridge = {  
  2.         init: init,  
  3.         send: send,  
  4.         registerHandler: registerHandler,  
  5.         callHandler: callHandler,  
  6.         _fetchQueue: _fetchQueue,  
  7.         _handleMessageFromObjC: _handleMessageFromObjC  
  8.     }  
window.WebViewJavascriptBridge = {
		init: init,
		send: send,
		registerHandler: registerHandler,
		callHandler: callHandler,
		_fetchQueue: _fetchQueue,
		_handleMessageFromObjC: _handleMessageFromObjC
	}

方法的實現:

[javascript] view plain copy print ?
  1. <span style="white-space: pre;">    </span>/* 
  2.      *初始化方法,注入默認的消息處理器 
  3.      *默認的消息處理器用於在處理來自objc的消息時,若是該消息沒有設置處理器,則採用默認處理器處理 
  4.      */  
  5.     function init(messageHandler) {  
  6.         if (WebViewJavascriptBridge._messageHandler) { throw new Error('WebViewJavascriptBridge.init called twice') }  
  7.         WebViewJavascriptBridge._messageHandler = messageHandler  
  8.         var receivedMessages = receiveMessageQueue  
  9.         receiveMessageQueue = null  
  10.         //若是接收隊列有消息,則處理  
  11.         for (var i=0; i<receivedMessages.length; i++) {  
  12.             _dispatchMessageFromObjC(receivedMessages[i])  
  13.         }  
  14.     }  
  15.   
  16.   
  17. <span style="white-space: pre;">    </span>/* 
  18.      *發送消息並設置回調 
  19.      */  
  20.     function send(data, responseCallback) {  
  21.         _doSend({ data:data }, responseCallback)  
  22.     }  
  23.       
  24.     /* 
  25.      *註冊消息處理器 
  26.      */  
  27.     function registerHandler(handlerName, handler) {  
  28.         messageHandlers[handlerName] = handler  
  29.     }  
  30.       
  31.   
  32.     /* 
  33.      *調用處理器並設置回調 
  34.      */  
  35.     function callHandler(handlerName, data, responseCallback) {  
  36.         _doSend({ data:data, handlerName:handlerName }, responseCallback)  
  37.     }  
	/*
	 *初始化方法,注入默認的消息處理器
	 *默認的消息處理器用於在處理來自objc的消息時,若是該消息沒有設置處理器,則採用默認處理器處理
	 */
	function init(messageHandler) {
		if (WebViewJavascriptBridge._messageHandler) { throw new Error('WebViewJavascriptBridge.init called twice') }
		WebViewJavascriptBridge._messageHandler = messageHandler
		var receivedMessages = receiveMessageQueue
		receiveMessageQueue = null
		//若是接收隊列有消息,則處理
		for (var i=0; i<receivedMessages.length; i++) {
			_dispatchMessageFromObjC(receivedMessages[i])
		}
	}


 /* *發送消息並設置回調 */ function send(data, responseCallback) { _doSend({ data:data }, responseCallback) } /* *註冊消息處理器 */ function registerHandler(handlerName, handler) { messageHandlers[handlerName] = handler } /* *調用處理器並設置回調 */ function callHandler(handlerName, data, responseCallback) { _doSend({ data:data, handlerName:handlerName }, responseCallback) } 

涉及到的兩個內部方法:

[javascript] view plain copy print ?
  1. <span style="white-space: pre;">    </span>/* 
  2.      *內部方法:消息的發送 
  3.      */  
  4.     function _doSend(message, responseCallback) {  
  5.         //若是定義了回調  
  6.         if (responseCallback) {  
  7.             //爲回調對象產生惟一標識  
  8.             var callbackId = 'js_cb_'+(uniqueId++)  
  9.             //並存儲到一個集合對象裏  
  10.             responseCallbacks[callbackId] = responseCallback  
  11.             //新增一個key-value對- 'callbackId':callbackId  
  12.             message['callbackId'] = callbackId  
  13.         }  
  14.         sendMessageQueue.push(JSON.stringify(message))  
  15.         messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE  
  16.     }  
  17.   
  18.   
  19. <span style="white-space: pre;">    </span>/* 
  20.      *內部方法:處理來自objc的消息 
  21.      */  
  22.     function _dispatchMessageFromObjC(messageJSON) {  
  23.         setTimeout(function _timeoutDispatchMessageFromObjC() {  
  24.             var message = JSON.parse(messageJSON)  
  25.             var messageHandler  
  26.               
  27.             if (message.responseId) {  
  28.                 //取出回調函數對象並執行  
  29.                 var responseCallback = responseCallbacks[message.responseId]  
  30.                 responseCallback(message.error, message.responseData)  
  31.                 delete responseCallbacks[message.responseId]  
  32.             } else {  
  33.                 var response  
  34.                 if (message.callbackId) {  
  35.                     var callbackResponseId = message.callbackId  
  36.                     response = {  
  37.                         respondWith: function(responseData) {  
  38.                             _doSend({ responseId:callbackResponseId, responseData:responseData })  
  39.                         },  
  40.                         respondWithError: function(error) {  
  41.                             _doSend({ responseId:callbackResponseId, error:error })  
  42.                         }  
  43.                     }  
  44.                 }  
  45.                   
  46.                 var handler = WebViewJavascriptBridge._messageHandler  
  47.                 //若是消息中已包含消息處理器,則使用該處理器;不然使用默認處理器  
  48.                 if (message.handlerName) {  
  49.                     handler = messageHandlers[message.handlerName]  
  50.                 }  
  51.                   
  52.                 try {  
  53.                     handler(message.data, response)  
  54.                 } catch(exception) {  
  55.                     console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception)  
  56.                 }  
  57.             }  
  58.         })  
  59.     }  
	/*
	 *內部方法:消息的發送
	 */
	function _doSend(message, responseCallback) {
		//若是定義了回調
		if (responseCallback) {
			//爲回調對象產生惟一標識
			var callbackId = 'js_cb_'+(uniqueId++)
			//並存儲到一個集合對象裏
			responseCallbacks[callbackId] = responseCallback
			//新增一個key-value對- 'callbackId':callbackId
			message['callbackId'] = callbackId
		}
		sendMessageQueue.push(JSON.stringify(message))
		messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE
	}


 /* *內部方法:處理來自objc的消息 */ function _dispatchMessageFromObjC(messageJSON) { setTimeout(function _timeoutDispatchMessageFromObjC() { var message = JSON.parse(messageJSON) var messageHandler if (message.responseId) { //取出回調函數對象並執行 var responseCallback = responseCallbacks[message.responseId] responseCallback(message.error, message.responseData) delete responseCallbacks[message.responseId] } else { var response if (message.callbackId) { var callbackResponseId = message.callbackId response = { respondWith: function(responseData) { _doSend({ responseId:callbackResponseId, responseData:responseData }) }, respondWithError: function(error) { _doSend({ responseId:callbackResponseId, error:error }) } } } var handler = WebViewJavascriptBridge._messageHandler //若是消息中已包含消息處理器,則使用該處理器;不然使用默認處理器 if (message.handlerName) { handler = messageHandlers[message.handlerName] } try { handler(message.data, response) } catch(exception) { console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception) } } }) } 

還有兩個js方法是供native端直接調用的方法(它們自己也是爲native端服務的):

[javascript] view plain copy print ?
  1. <span style="white-space: pre;">    </span>/* 
  2.      *得到隊列,將隊列中的每一個元素用分隔符分隔以後連成一個字符串【native端調用】 
  3.      */  
  4.     function _fetchQueue() {  
  5.         var messageQueueString = sendMessageQueue.join(MESSAGE_SEPARATOR)  
  6.         sendMessageQueue = []  
  7.         return messageQueueString  
  8.     }  
  9.   
  10.   
  11. <span style="white-space: pre;">    </span>/* 
  12.      *處理來自ObjC的消息【native端調用】 
  13.      */  
  14.     function _handleMessageFromObjC(messageJSON) {  
  15.         //若是接收隊列對象存在則入隊該消息,不然直接處理  
  16.         if (receiveMessageQueue) {  
  17.             receiveMessageQueue.push(messageJSON)  
  18.         } else {  
  19.             _dispatchMessageFromObjC(messageJSON)  
  20.         }  
  21.     }  
	/*
	 *得到隊列,將隊列中的每一個元素用分隔符分隔以後連成一個字符串【native端調用】
	 */
	function _fetchQueue() {
		var messageQueueString = sendMessageQueue.join(MESSAGE_SEPARATOR)
		sendMessageQueue = []
		return messageQueueString
	}


 /* *處理來自ObjC的消息【native端調用】 */ function _handleMessageFromObjC(messageJSON) { //若是接收隊列對象存在則入隊該消息,不然直接處理 if (receiveMessageQueue) { receiveMessageQueue.push(messageJSON) } else { _dispatchMessageFromObjC(messageJSON) } } 

最後還有一段代碼就是,定義一個事件並觸發,同時設置設置上面定義的WebViewJavascriptBridge對象爲事件的一個屬性:

 

[javascript] view plain copy print ?
  1. <span style="white-space: pre;">    </span>var doc = document  
  2.     _createQueueReadyIframe(doc)  
  3.     //建立並實例化一個事件對象  
  4.     var readyEvent = doc.createEvent('Events')  
  5.     readyEvent.initEvent('WebViewJavascriptBridgeReady')  
  6.     readyEvent.bridge = WebViewJavascriptBridge  
  7.     //觸發事件  
  8.     doc.dispatchEvent(readyEvent)  
	var doc = document
	_createQueueReadyIframe(doc)
	//建立並實例化一個事件對象
	var readyEvent = doc.createEvent('Events')
	readyEvent.initEvent('WebViewJavascriptBridgeReady')
	readyEvent.bridge = WebViewJavascriptBridge
	//觸發事件
	doc.dispatchEvent(readyEvent)

Native端實現

 

其實大體跟上面的相似,只是由於語法不一樣(因此我上面才說兩端是對等的):

WebViewJavascriptBridge.h/.m

它其實能夠看做UIWebView的Controller,實現了UIWebViewDelegate協議:

  1. @interface WebViewJavascriptBridge : NSObject <UIWebViewDelegate>  
  2. + (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler;  
  3. + (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id <UIWebViewDelegate>)webViewDelegate handler:(WVJBHandler)handler;  
  4. + (void)enableLogging;  
  5. - (void)send:(id)message;  
  6. - (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback;  
  7. - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;  
  8. - (void)callHandler:(NSString*)handlerName;  
  9. - (void)callHandler:(NSString*)handlerName data:(id)data;  
  10. - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;  
  11. @end  
@interface WebViewJavascriptBridge : NSObject <UIWebViewDelegate>
+ (id)bridgeForWebView:(UIWebView*)webView handler:(WVJBHandler)handler;
+ (id)bridgeForWebView:(UIWebView*)webView webViewDelegate:(id <UIWebViewDelegate>)webViewDelegate handler:(WVJBHandler)handler;
+ (void)enableLogging;
- (void)send:(id)message;
- (void)send:(id)message responseCallback:(WVJBResponseCallback)responseCallback;
- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;
- (void)callHandler:(NSString*)handlerName;
- (void)callHandler:(NSString*)handlerName data:(id)data;
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;
@end

方法的實現實際上是跟前面相似的,這裏咱們只看一下UIWebView的一個協議方法

shouldStartLoadWithRequest:

 

  1. - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {  
  2.     if (webView != _webView) { return YES; }  
  3.     NSURL *url = [request URL];  
  4.     if ([[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME]) {  
  5.         //隊列中有數據  
  6.         if ([[url host] isEqualToString:QUEUE_HAS_MESSAGE]) {  
  7.             //刷出隊列中數據  
  8.             [self _flushMessageQueue];  
  9.         } else {  
  10.             NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]);  
  11.         }  
  12.         return NO;  
  13.     } else if (self.webViewDelegate) {  
  14.         return [self.webViewDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];  
  15.     } else {  
  16.         return YES;  
  17.     }  
  18. }  
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (webView != _webView) { return YES; }
    NSURL *url = [request URL];
    if ([[url scheme] isEqualToString:CUSTOM_PROTOCOL_SCHEME]) {
		//隊列中有數據
        if ([[url host] isEqualToString:QUEUE_HAS_MESSAGE]) {
			//刷出隊列中數據
            [self _flushMessageQueue];
        } else {
            NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", CUSTOM_PROTOCOL_SCHEME, [url path]);
        }
        return NO;
    } else if (self.webViewDelegate) {
        return [self.webViewDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
    } else {
        return YES;
    }
}

使用示例

UI端

 

 

[javascript] view plain copy print ?
  1. <span style="white-space: pre;">    </span>//給WebViewJavascriptBridgeReady事件註冊一個Listener  
  2.     document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false)  
  3.     <span style="white-space: pre;">    </span>//事件的響應處理  
  4.     function onBridgeReady(event) {  
  5.         var bridge = event.bridge  
  6.         var uniqueId = 1  
  7.         <span style="white-space: pre;">    </span>//日誌記錄  
  8.         function log(message, data) {  
  9.             var log = document.getElementById('log')  
  10.             var el = document.createElement('div')  
  11.             el.className = 'logLine'  
  12.             el.innerHTML = uniqueId++ + '. ' + message + (data ? ': ' + JSON.stringify(data) : '')  
  13.             if (log.children.length) { log.insertBefore(el, log.children[0]) }  
  14.             else { log.appendChild(el) }  
  15.         }  
  16.         <span style="white-space: pre;">    </span>//初始化操做,並定義默認的消息處理邏輯  
  17.         bridge.init(function(message) {  
  18.             log('JS got a message', message)  
  19.         })  
  20.         <span style="white-space: pre;">    </span>//註冊一個名爲testJavascriptHandler的處理器,並定義用於響應的處理邏輯  
  21.         bridge.registerHandler('testJavascriptHandler', function(data, response) {  
  22.             log('JS handler testJavascriptHandler was called', data)  
  23.             response.respondWith({ 'Javascript Says':'Right back atcha!' })  
  24.         })  
  25.   
  26.         <span style="white-space: pre;">    </span>//建立一個發送消息給native端的按鈕  
  27.         var button = document.getElementById('buttons').appendChild(document.createElement('button'))  
  28.         button.innerHTML = 'Send message to ObjC'  
  29.         button.ontouchstart = function(e) {  
  30.             e.preventDefault()  
  31.             <span style="white-space: pre;">        </span>//發送消息  
  32.             bridge.send('Hello from JS button')  
  33.         }  
  34.   
  35.         document.body.appendChild(document.createElement('br'))  
  36.   
  37.         <span style="white-space: pre;">    </span>//建立一個用於調用native端處理器的按鈕  
  38.         var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))  
  39.         callbackButton.innerHTML = 'Fire testObjcCallback'  
  40.         callbackButton.ontouchstart = function(e) {  
  41.             e.preventDefault()  
  42.             log("Calling handler testObjcCallback")  
  43.             //調用名爲testObjcCallback的native端處理器,並傳遞參數,同時設置回調處理邏輯  
  44.             bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {  
  45.                 log('Got response from testObjcCallback', response)  
  46.             })  
  47.         }  
  48.     }  
	//給WebViewJavascriptBridgeReady事件註冊一個Listener
	document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false)
     //事件的響應處理 function onBridgeReady(event) { var bridge = event.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 + (data ? ': ' + JSON.stringify(data) : '') if (log.children.length) { log.insertBefore(el, log.children[0]) } else { log.appendChild(el) } }  //初始化操做,並定義默認的消息處理邏輯 bridge.init(function(message) { log('JS got a message', message) })  //註冊一個名爲testJavascriptHandler的處理器,並定義用於響應的處理邏輯 bridge.registerHandler('testJavascriptHandler', function(data, response) { log('JS handler testJavascriptHandler was called', data) response.respondWith({ 'Javascript Says':'Right back atcha!' }) })  //建立一個發送消息給native端的按鈕 var button = document.getElementById('buttons').appendChild(document.createElement('button')) button.innerHTML = 'Send message to ObjC' button.ontouchstart = function(e) { e.preventDefault()  //發送消息 bridge.send('Hello from JS button') } document.body.appendChild(document.createElement('br'))  //建立一個用於調用native端處理器的按鈕 var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button')) callbackButton.innerHTML = 'Fire testObjcCallback' callbackButton.ontouchstart = function(e) { e.preventDefault() log("Calling handler testObjcCallback") //調用名爲testObjcCallback的native端處理器,並傳遞參數,同時設置回調處理邏輯 bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) { log('Got response from testObjcCallback', response) }) } } 

Native端

  1. //實例化一個webview並加入到window中去  
  2.     UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds];  
  3.     [self.window addSubview:webView];  
  4.       
  5.     //啓用日誌記錄  
  6.     [WebViewJavascriptBridge enableLogging];  
  7.       
  8.     //實例化WebViewJavascriptBridge並定義native端的默認消息處理器  
  9.     _bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse *response) {  
  10.         NSLog(@"ObjC received message from JS: %@", data);  
  11.         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ObjC got message from Javascript:" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];  
  12.         [alert show];  
  13.     }];  
  14.       
  15.     //註冊一個供UI端調用的名爲testObjcCallback的處理器,並定義用於響應的處理邏輯  
  16.     [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponse *response) {  
  17.         NSLog(@"testObjcCallback called: %@", data);  
  18.         [response respondWith:@"Response from testObjcCallback"];  
  19.     }];  
  20.       
  21.     //發送一條消息給UI端並定義回調處理邏輯  
  22.     [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id error, id responseData) {  
  23.         if (error) { NSLog(@"Uh oh - I got an error: %@", error); }  
  24.         NSLog(@"objc got response! %@ %@", error, responseData);  
  25.     }];  
  26.       
  27.     //調用一個在UI端定義的名爲testJavascriptHandler的處理器,沒有定義回調  
  28.     [_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]];  
  29.       
  30.     [self renderButtons:webView];  
  31.     [self loadExamplePage:webView];  
  32.       
  33.     //單純發送一條消息給UI端  
  34.     [_bridge send:@"A string sent from ObjC after Webview has loaded."];  
//實例化一個webview並加入到window中去
    UIWebView* webView = [[UIWebView alloc] initWithFrame:self.window.bounds];
    [self.window addSubview:webView];
    
    //啓用日誌記錄
    [WebViewJavascriptBridge enableLogging];
    
    //實例化WebViewJavascriptBridge並定義native端的默認消息處理器
    _bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse *response) {
        NSLog(@"ObjC received message from JS: %@", data);
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ObjC got message from Javascript:" message:data delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
    }];
    
    //註冊一個供UI端調用的名爲testObjcCallback的處理器,並定義用於響應的處理邏輯
    [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponse *response) {
        NSLog(@"testObjcCallback called: %@", data);
        [response respondWith:@"Response from testObjcCallback"];
    }];
    
    //發送一條消息給UI端並定義回調處理邏輯
    [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id error, id responseData) {
        if (error) { NSLog(@"Uh oh - I got an error: %@", error); }
        NSLog(@"objc got response! %@ %@", error, responseData);
    }];
    
    //調用一個在UI端定義的名爲testJavascriptHandler的處理器,沒有定義回調
    [_bridge callHandler:@"testJavascriptHandler" data:[NSDictionary dictionaryWithObject:@"before ready" forKey:@"foo"]];
    
    [self renderButtons:webView];
    [self loadExamplePage:webView];
    
    //單純發送一條消息給UI端
    [_bridge send:@"A string sent from ObjC after Webview has loaded."];

項目運行截圖:

相關文章
相關標籤/搜索