WebViewJavaScriptBridge的原理解析


理解WebViewJavaScriptBridge原理

前提條件都是需要bridge在OC實例化,然后二者的互調才可以進行下去

_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

實例化的原理是:JSBridge里面有UIWebview和JSBridgeBase的實例,然后分別成為二者的代理,負責協調雙方的工作

第一部分:js調用OC方法:

由OC注冊,JS主動觸發(調用callhandler方法)

1.執行前提條件

2.OC在注冊(registerHandler)的時候,OC會注冊一個回調函數

[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback)

,該回調函數包括一個注冊事件和一個回調方法,JSB中的base實例會把該注冊事件放進到base的一個消息池子(負責接受多個OC注冊事件)中,方便后續處理

3.網頁加載出來后整個oc的執行流程

相當於JS的注冊綁定方法--->當UIWebview把該網頁加載出來的時候,在該html文件中會通過JS的iframe元素執行JS和OC端的綁定。

該方法是由於webview的delegate設置為了JSB,所以會在JSB中觸發其代理方法:shouldStartLoadWithRequest,然后在該方法中進行如下操作:

根據url(此時的url是由上述的iframe元素帶進來的,類似:wvjbscheme://BRIDGE_LOADED ) ,來決定此時是走registerHandler 還是 callHandler方法,此時是register方法,那么則執行JSBridgeBase的injectJavascriptFile方法(正如函數名一樣,此時執行在工程里面放置的JS文件(在我們的工程里面由於要兼容JSBridge的歷史版本,所以這里是在webViewDidFinishLoad里面直接調用injectJavascriptFile方法)),這個文件的主要作用就是向OC發消息來定義一些常量,注冊一些實例,定義一些回調方法,方便在OC的邏輯中進行處理和跟蹤,文件執行完畢后,接下來就會查找在base中時候有OC要發送給JS的回調信息,沒有則執行結束(這里顯然沒有)

4.oc和js相互綁定過后,此時由JS觸發OC函數

點擊JS上的button會觸發callHandler,會觸發代理shouldStartLoadWithRequest:
此時由於經由上述的JS文件執行的時候會執行一個叫做window.WebViewJavascriptBridge的注冊

window.WebViewJavascriptBridge = {
		registerHandler: registerHandler,
		callHandler: callHandler,
		disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,
		_fetchQueue: _fetchQueue,
		_handleMessageFromObjC: _handleMessageFromObjC
	};

由於js主動觸發了callHandler,url所以變成了
wvjbscheme://WVJB_QUEUE_MESSAGE ,所以此時會走一個執行js函數的方法(猜測是通過上述js文件的作用從而能夠解析出JS傳遞過來的信息)來從網頁上獲得網頁的傳遞過來的信息!

{
  "callbackId" : "cb_2_1468844907930",
  "handlerName" : "testObjcCallback",
  "data" : {
    "foo" : "bar"
  }
}

然后進入base的flushMessageQueue:函數,在里面通過解析該dict,從而獲得注冊事件名handlerName,然后獲得該事件的回調,並調用那個事件的回調block

handler(message[@"data"], responseCallback);

至此,整個JS回調OC過程完成,達到了JS給OC發送數據的目的,同時如果OC想要給JS發送消息,只需把信息放進responseCallback就會回調給JS(方法就是第二部分的內容),以達到互相通信的目的



第二部分:OC調用js方法:

由js注冊,OC主動觸發(調用callhandler方法)

1.執行前提條件

2.網頁加載出來后整個oc的執行流程

相當於JS的注冊方法--->當UIWebview把該網頁加載出來的時候,在該html文件中會通過JS的iframe元素執行JS和OC端的綁定。

該方法的由於webview的delegate設置為了JSb,所以會在JSB中觸發其代理方法:shouldStartLoadWithRequest,然后在該方法中進行如下操作:

根據url(此時的url是由上述的iframe元素帶進來的,類似:wvjbscheme://BRIDGE_LOADED ) ,來決定此時是走registerHandler 還是 callHandler方法,此時是register方法,那么則執行JSBridgeBase的injectJavascriptFile方法(正如函數名一樣,此時執行在工程里面放置的JS文件),這個文件的主要作用就是向OC發消息來定義一些常量,注冊一些實例,定義一些回調方法,方便在OC的邏輯中進行處理和跟蹤,
其中會執行一個叫做window.WebViewJavascriptBridge的注冊

window.WebViewJavascriptBridge = {
		registerHandler: registerHandler,
		callHandler: callHandler,
		disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,
		_fetchQueue: _fetchQueue,
		_handleMessageFromObjC: _handleMessageFromObjC
	};

由於js函數中一進來便主動觸發了registerHandler,所以url變成了
wvjbscheme://WVJB_QUEUE_MESSAGE
文件執行完畢后,會在JSB中執行

else if ([_base isQueueMessageURL:url]) {
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
            [_base flushMessageQueue:messageQueueString];
            }

恰好此時url 滿足情況,則進入消息分發流程,但是由於此時messageQueueString什么也沒有,所以直接跳出

3.OC和js相互綁定過后,此時由OC函數觸發JS

點擊OC的button,觸發OC函數

[_bridge callHandler:@"testJavascriptHandler" data:@{@"name": @"wayne"} responseCallback:^(id responseData)

調用Base的

- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName

使用dictionary進行消息拼接,形如:

{
    callbackId = "objc_cb_1";//定義OC的回調id
    data =     {
        name = wayne;
    };//OC傳遞給JS的數據
    handlerName = testJavascriptHandler;//為了區分是哪一個注冊事件,以便后續的消息分發
}

封裝完成過后,會調用[self _dispatchMessage:message]來進行消息分發,消息分發是在主線程里面執行的,消息的內容經過再次封裝過后形似:

WebViewJavascriptBridge._handleMessageFromObjC('{\"callbackId\":\"objc_cb_1\",\"data\":{\"name\":\"wayne\"},\"handlerName\":\"testJavascriptHandler\"}');

WebViewJavascriptBridge._handleMessageFromObjC-->查看JS文件可知,這個文件是給JS使用的,會執行_handleMessageFromObjC的方法把消息分發給JS中的registerHandler中的方法體,OC回調過程結束!!

4.JS傳遞數據給OC

但是此時在執行JS中的代碼的時候發現有回調block,則會執行改block

然后會再次執行UIWebview的代理方法:shouldStartLoadWithRequest函數,此時url已經是
wvjbscheme://WVJB_QUEUE_MESSAGE
文件執行完畢后,會在JSB中執行

else if ([_base isQueueMessageURL:url]) {
		NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
        [_base flushMessageQueue:messageQueueString];
      }

messageQueueString由第一部分知識可知:是JS傳遞過來的數據:

[{
"handlerName":"testJavascriptHandler",
"responseId":"objc_cb_1",
"responseData":
		{"Javascript Says":"Right back atcha!==>test"}
}]

執行flushMessageQueue函數:並在里面執行block函數體,獲得JS傳遞過來的數據

至此,互相傳遞數據過程完畢!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM