WebViewJavascriptBridge source code exploration-view the interaction process between OC and JS and between wkwebviewjs oc
Today, I checked the source code of the third-party library WebViewJavascriptBridge that implements interaction between OC code and JS Code. We know that oc calls js methods. The system provides the stringByEvaluatingJavaScriptFromString function.
. Now I want to know how js calls the oc method and share the exploration process.
There are not many source code, just the header file WebViewJavascriptBridge. h and the implementation file WebViewJavascriptBridge. m, and a js file, so that you can call the oc method on the js side or the js method on the oc side.
First, implement a simple demo of mutual calling between oc and js, and append the scenario of mutual calling between oc and js used in the simulation project:
I. Then let's talk about how js calls the oc method. How are they implemented? Three library files
We track the process of loading UIWebView by the oc controller and the process of calling the oc method by js.
Contains the initial js Code.
In this js file, a WebViewJavascriptBridge script object is created, and a hidden iframe tag is created. Each time JavaScript calls the oc method, the src of the iframe tag is modified to trigger the proxy listening method of UIWebView.
; (Function () {if (window. webViewJavascriptBridge) {return} var messagingIframe var sendMessageQueue = [] var receiveMessageQueue = [] var messageHandlers = {} var response = 'hangzhou' var QUEUE_HAS_MESSAGE = '_ callback _' var responseCallbacks = {} var uniqueId = 1 function _ createQueueReadyIframe (doc) {messagingIframe = doc. createElement ('iframe') messagingIframe. st Yle. display = 'none' messagingIframe. src = CUSTOM_PROTOCOL_SCHEME + ': //' + QUEUE_HAS_MESSAGE doc.doc umentElement. appendChild (messagingIframe)} function init (messageHandler) {if (WebViewJavascriptBridge. _ messageHandler) {throw new Error ('webviewjavascriptbridge. init called twice ')} WebViewJavascriptBridge. _ messageHandler = messageHandler var receivedMessages = receiveMessageQueue receivemesages EQueue = 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}, respons ECallback)} function _ doSend (message, responseCallback) {if (responseCallback) {var callbackId = 'cb _ '+ (uniqueId ++) +' _ '+ new Date (). getTime () responseCallbacks [callbackId] = responseCallback message ['callbackid'] = callbackId} sendMessageQueue. push (message); // put the dictionary into an array // modify the src attribute of the iframe tag, and the UIWebView listener executes the proxy method messagingIframe. src = CUSTOM_PROTOCOL_SCHEME + ': //' + QUEUE_HAS_MESSAGE;} function _ fetch Queue () {// convert the json array to the json string 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. han DlerName) {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, _ blank: _ blank} var doc = document _ blank (doc) var readyEvent = doc. createEvent ('events') readyEvent. initEvent ('webviewjavascriptbridgeready') readyEvent. bridge = WebViewJavascriptBridge doc. dispatchEvent (readyEvent )})();View Code
2. uiwebview.pdf the custom HTML page testjsbridge.html contains the script to register the oc method ID for js call and the js ID for oc call.
<Html>
3. Click the html Tag button to trigger the js event.
// Set the event var callbackButton = document for the tag button. getElementById ('jsbtn '); callbackButton. onclick = function (e) {e. preventDefault (); // register the js_Call_Objc_Func ID to facilitate js to send messages to IOS bridge. callHandler ('js _ Call_Objc_Func ', {id: 1, info: 'Hello, iOS, I'm coming from the js side! '}, Function (response ){});}
We track the bridge. callHandler method and enter WebViewJavascriptBridge. js.
Var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'
Var QUEUE_HAS_MESSAGE = '_ WVJB_QUEUE_MESSAGE __'
MessagingIframe is an iframe tag. Click the custom html button tag to trigger the js event and enter callHandler --> _ doSend,
When the messagingIframe label src is re-assigned, the proxy method of UIWebView is triggered (the src value is always: wvjbscheme: // _ WVJB_QUEUE_MESSAGE _, which can also be customized, this will be used as an identifier for determining when you enter the oc UIWebView proxy method ).
Follow up the subsequent execution process:
So far, js has successfully called oc
Summarize the process of js calling oc:
--> Trigger js events
--> Store the "js_Call_Objc_Func" parameter to the js array sendMessageQueue.
--> Re-assign the src attribute of the iframe tag, trigger the UIWebView proxy method, and enter the corresponding processing method according to the src value.
--> Call js method _ fetchQueue In the oc method to obtain all parameters in the js array.
--> Based on the imported custom registration ID js_Call_Objc_Func, find the matching block from the oc dictionary _ messageHandlers, and finally execute the block, which contains the subsequent code for custom processing.
Ii. js call process by oc
Initiated from within oc
--> Call the callHandler method of bridge to pass in the required parameters and custom registration ID
--> Finally, use the UIWebView system method stringByEvaluatingJavaScriptFromString to call the js script WebViewJavascriptBridge. _ handleMessageFromObjC to pass parameters.
--------------------------------------------- End --------------------------------------
Download DEMO
Github address: https://github.com/xiaotanit/Tan_WebViewJavaScriptBridge
In addition, the following url issue is recorded:
Assume the loaded url is: http://baidu.com /? Search = blog
In this way, the url with Chinese parameters loaded by UIWebView cannot be displayed. You must escape Chinese characters to display the url.
Use the string method stringByAddingPercentEncodingWithAllowedCharacters to escape Chinese characters.
NSString * str = @ "The http://baidu.com /? Search = blog "; // str = [str stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; str = [str character: [NSCharacterSet characterSetWithCharactersInString: @ "'# % ^ {}\" [] |\<> "]. invertedSet];
NSURL * url = [NSURL URLWithString: str];
NSURLRequest * request = [NSURLRequest requestWithURL: url];
Link: http://www.cnblogs.com/tandaxia/p/5699886.html