WebViewJavascriptBridge

lazy_boy發表於2018-05-21

JS Call OC

首先,需要在OC中註冊 JS 方法

[_bridge registerHandler:@"testObjcCallback"
                     handler:^(id data, WVJBResponseCallback responseCallback)
    {
        NSLog(@"testObjcCallback called: %@", data);
        responseCallback(@"Response from testObjcCallback");
    }];
複製程式碼

其中testObjcCallback就是JS呼叫OC方法 OC中在初始化的時候,需要註冊相關的JS方法。這樣OC這樣就保留了一份以JS函式名字的資訊(handlerName)。當JS呼叫OC的時候,會把JS自己的handlerName和data資料還有OC呼叫之後回撥的block,一起傳給JS工具類(callHandler方法可以選擇傳data資料)。JS工具類中callHandler函式會把handlerName和data資料封裝成一個 message型別的字典,然後呼叫_doSend方法。_doSend方法會根據responseCallback的有無來判斷 JS Call OC 後需不需要回撥。如果需要回撥的話JS應該把回撥的responseCallback傳遞過來,JS工具類會通過全域性的sendMessageQueue陣列來儲存傳送的message資訊。然後,改變 iframe 的 src 從而達到重新整理WebView的作用。

WKWebView

呼叫

- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction 
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
複製程式碼
UIWebView

呼叫

- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType
複製程式碼

OC會在上面的方法中攔截,由於JS提前和OC約定什麼樣的URL屬於互動,所以當OC攔截到相關的方法時,會呼叫JS方法拿到 當前的 message,同時OC會通過handlerName去檢測這個方法有沒有在OC中註冊。如果找到,那麼回撥這個block把JS的引數傳遞過去,並把OC回傳的引數,再次和JS傳遞過來的 callbackId 組成一個字典(注:這裡會把callbackId的key換成responseId),通過OC 執行JS _handleMessageFromObjC方法,JS會根據回傳的responseId去全域性陣列responseCallback裡面拿到回傳的block,呼叫後,刪除。 至此,整個 JS Call OC 流程結束。

總結如下:
  • OC 需要提前註冊 JS 方法,以便能夠響應JS的呼叫,他們直接通過handlerName來關聯
  • JS 調 OC 是 設定 callbackId 引數和 需要傳遞的 data資料,儲存在一個全域性的訊息陣列中,然後通過OC拿到所有的訊息,分別解析執行。而JS的回撥是在OC中把當前的callbackId的key替換成responseId。
  • JS 會把 responseCallback(JS的回撥block)放進一個全域性的字典中,以callbackId為鍵值,會把產生的訊息放進sendMessageQueue陣列中
  • OC回撥JS,作為JS呼叫OC完成的標誌,JS會去responseCallbacks中取出,呼叫後刪除。

OC Call JS

剛好實現流程反了過來,這時JS需要註冊OC的方法,OC通過 UIWebView:

- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
複製程式碼

或者 WKWebView

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
複製程式碼

來呼叫 JS 中_handleMessageFromObjC中的方法,把相關的引數一起帶上,JS解析OC傳過來的欄位通過 判斷 responseId 的有無來判斷是call還是reponse(迴應),並從messageHandlers取出提前註冊的JS方法中的block,迴應之後在通過改變iframe src的形式,同時把callbackId改成responseId回傳給OC,OC攔截到之後,在去比較執行,在響應。 整體流程圖如下:

WebViewJavascriptBridge