WebViewJavascriptBridge源碼探究--看OC和JS互動過程,wkwebviewjs互動oc

來源:互聯網
上載者:User

WebViewJavascriptBridge源碼探究--看OC和JS互動過程,wkwebviewjs互動oc

      今天把實現OC代碼和JS代碼互動的第三方庫WebViewJavascriptBridge源碼看了下,oc調用js方法我們是知道的,系統提供了stringByEvaluatingJavaScriptFromString函數

。現在主要是瞭解js是如何調用oc方法的,分享下探究過程。

   源碼不多,就一個標頭檔WebViewJavascriptBridge.h和實現檔案WebViewJavascriptBridge.m, 和一個js檔案,實現在js那邊可以調用oc方法,也可以在oc裡面調用js方法。

先,實現簡單的oc和js互相調用的demo, 另外附加一個類比項目中用到的oc和js互相調用情境:

  

 

一、然後說說js調用oc方法的原理,它們是如何?的?庫檔案三個

 

我們跟蹤下oc控制器載入UIWebView的過程和js調用oc方法過程

 

1、程式啟動,在自訂控制器裡,建立一個WebViewJavascriptBridge對象時,會載入WebViewJavascriptBridge.js.txt檔案,裡面是初始js代碼

     在這個js裡面,建立了一個WebViewJavascriptBridge指令碼對象,另外建立一個隱藏的iframe標籤:每次js調用oc方法,都是修改iframe標籤的src來觸發UIWebView的代理監聽方法

;(function() { if (window.WebViewJavascriptBridge) { return } var messagingIframe var sendMessageQueue = [] var receiveMessageQueue = [] var messageHandlers = {} var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme' var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__' var responseCallbacks = {} var uniqueId = 1 function _createQueueReadyIframe(doc) { messagingIframe = doc.createElement('iframe') messagingIframe.style.display = 'none' messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE doc.documentElement.appendChild(messagingIframe) } 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({ handlerName:handlerName, data:data }, responseCallback) } function _doSend(message, responseCallback) { if (responseCallback) { var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime() responseCallbacks[callbackId] = responseCallback message['callbackId'] = callbackId } sendMessageQueue.push(message); //將字典放入數組 //修改iframe標籤的src屬性,UIWebView監聽執行代理方法 messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; } function _fetchQueue() { //json數組轉成json字串 var messageQueueString = JSON.stringify(sendMessageQueue) sendMessageQueue = [] return messageQueueString } function _dispatchMessageFromObjC(messageJSON) { setTimeout(function _timeoutDispatchMessageFromObjC() { var message = JSON.parse(messageJSON) var messageHandler if (message.responseId) { var responseCallback = responseCallbacks[message.responseId] if (!responseCallback) { return; } responseCallback(message.responseData) delete responseCallbacks[message.responseId] } else { var responseCallback if (message.callbackId) { var callbackResponseId = message.callbackId responseCallback = function(responseData) { _doSend({ responseId:callbackResponseId, responseData:responseData }) } } var handler = WebViewJavascriptBridge._messageHandler if (message.handlerName) { handler = messageHandlers[message.handlerName] } try { handler(message.data, responseCallback) } catch(exception) { if (typeof console != 'undefined') { console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception) } } } }) } function _handleMessageFromObjC(messageJSON) { if (receiveMessageQueue) { receiveMessageQueue.push(messageJSON) } else { _dispatchMessageFromObjC(messageJSON) } } window.WebViewJavascriptBridge = { init: init, send: send, registerHandler: registerHandler, callHandler: callHandler, _fetchQueue: _fetchQueue, _handleMessageFromObjC: _handleMessageFromObjC } var doc = document _createQueueReadyIframe(doc) var readyEvent = doc.createEvent('Events') readyEvent.initEvent('WebViewJavascriptBridgeReady') readyEvent.bridge = WebViewJavascriptBridge doc.dispatchEvent(readyEvent)})();View Code

 

2、UIWebView載入我們自訂的html頁面TestJSBridge.html, 裡面有指令碼註冊js調用oc方法標識,和oc調用js標識

<html> <head> <meta charset="utf-8"/> <style type="text/css"> html { font-family:Helvetica; color:#222; background:#D5FFFD; border: 5px dashed blue;} .rowH3{margin: 0px; text-align: center;} .jsBtn{font-size: 18px;} </style> </head> <body> <h3 class="rowH3">測試OC和JS互相調用</h3> <button class="jsBtn" id="jsBtn">JS調用OC方法</button> <div id="logDiv"><!-- 列印日誌 --></div> </body></html><script type="text/javascript"> window.onerror = function(err) { printLog(err); } function connectWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBridge) { callback(WebViewJavascriptBridge); } else { document.addEventListener('WebViewJavascriptBridgeReady', function() { callback(WebViewJavascriptBridge); }, false); } } var uniqueId = 1; //日誌列印方法 function printLog(data) { var logObj = document.getElementById('logDiv'); var el = document.createElement('div'); el.className = 'logLine'; el.innerHTML = uniqueId++ + ': ' + JSON.stringify(data); //json轉字串 if (logObj.children.length) { logObj.insertBefore(el, logObj.children[0]) } else { logObj.appendChild(el) } } //初始化調用函數connectWebViewJavascriptBridge connectWebViewJavascriptBridge(function(bridge) { bridge.init(function(message, responseCallback) {}); //註冊js回應程式法,響應OC調用,標識objc_Call_JS_Func bridge.registerHandler('objc_Call_JS_Func', function(data, responseCallback) { printLog(data); //列印oc傳過來的參數 }); //給標籤按鈕設定點擊事件 var callbackButton = document.getElementById('jsBtn'); callbackButton.onclick = function(e) { e.preventDefault(); //註冊標識js_Call_Objc_Func,便於js給IOS發送訊息 bridge.callHandler('js_Call_Objc_Func', {id: 1, info: 'hello, iOS, 我從js那邊過來!'}, function(response) { }); } }); </script>View Code

 

3、點擊html標籤按鈕,觸發js事件

//給標籤按鈕設定點擊事件var callbackButton = document.getElementById('jsBtn');callbackButton.onclick = function(e) {e.preventDefault();            //註冊標識js_Call_Objc_Func,便於js給IOS發送訊息bridge.callHandler('js_Call_Objc_Func', {id: 1, info: 'hello, iOS, 我從js那邊過來!'},  function(response) { });}

 我們跟蹤bridge.callHandler方法,進入WebViewJavascriptBridge.js

  var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'

  var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'

    messagingIframe是個iframe標籤,點擊我們自訂html按鈕標籤,觸發js事件,最後進入callHandler -->  _doSend ,

當messagingIframe標籤src重新賦值時,會觸發UIWebView的代理方法(src的值一直是:wvjbscheme://__WVJB_QUEUE_MESSAGE__ ,也可自訂,這個在進入oc UIWebView代理方法時會用來作為判斷標識)。

跟蹤後面執行的過程:

  

至此,js調用oc成功

總結js調用oc過程:

-->   觸發js事件

-->   把要傳入參數和自訂註冊標識“js_Call_Objc_Func”存入js數組sendMessageQueue

 -->  重新賦值iframe標籤的src屬性,觸發UIWebView代理方法, 根據src的值進入相應處理方法中

-->   在oc方法裡面調用js方法_fetchQueue, 擷取js數組裡面所有的參數  

-->   根據傳入的自訂註冊標識 js_Call_Objc_Func  從oc字典_messageHandlers找出匹配block, 最後執行block,裡面有我們自訂處理的後續代碼

 

二、oc調用js過程

從oc內部發起

-- > 調用bridge的callHandler方法,傳入需要的參數和自訂註冊標識

--> 最後使用UIWebView系統方法stringByEvaluatingJavaScriptFromString調用js指令碼WebViewJavascriptBridge._handleMessageFromObjC 完成參數的傳遞

  

---------------------------------------------  end --------------------------------------

DEMO下載

github地址:https://github.com/xiaotanit/Tan_WebViewJavaScriptBridge

 

另外記錄一個UIWebView不能載入帶中文參數的url問題:

假設載入url為:http://baidu.com/?search=部落格園

這樣UIWebView載入這個帶中文參數的url, 是不能顯示的,需要把中文進行轉義,才能顯示。

使用字串方法stringByAddingPercentEncodingWithAllowedCharacters對中文進行轉義

NSString *str = @"http://baidu.com/?search=部落格園";  //  str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "].invertedSet];    
NSURL *url = [NSURL URLWithString:str];

  NSURLRequest *request = [NSURLRequest requestWithURL:url];

 

原文連結:http://www.cnblogs.com/tandaxia/p/5699886.html

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.