WebViewJavaScriptBridge的原理解析

理解WebViewJavaScriptBridge原理

前提條件都是須要bridge在OC實例化,而後兩者的互調才能夠進行下去javascript

_bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

實例化的原理是:JSBridge裏面有UIWebview和JSBridgeBase的實例,而後分別成爲兩者的代理,負責協調雙方的工做html

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

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

1.執行前提條件

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

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

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

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

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

該方法是因爲webview的delegate設置爲了JSB,因此會在JSB中觸發其代理方法:shouldStartLoadWithRequest,而後在該方法中進行以下操做:fetch

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

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

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

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

因爲js主動觸發了callHandler,url因此變成了
wvjbscheme://WVJB_QUEUE_MESSAGE ,因此此時會走一個執行js函數的方法(猜想是經過上述js文件的做用從而可以解析出JS傳遞過來的信息)來從網頁上得到網頁的傳遞過來的信息!spa

{
  "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傳遞過來的數據

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

相關文章
相關標籤/搜索