WebViewJavascriptBridge 調(diào)用過程(二)

JS調(diào)用OC過程

以WKWebView為例
1、OC端注冊

  [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"testObjcCallback called: %@", data);
        responseCallback(@"Response from testObjcCallback");
    }];
// 實際調(diào)用
- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler {
//將回調(diào)blcok存儲在一個全局字典中
    _base.messageHandlers[handlerName] = [handler copy];
}

2、JS端調(diào)用OC端注冊的名稱,并傳參數(shù)設(shè)置回調(diào)函數(shù)。

bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
     log('JS got response', response)
})
//實際調(diào)用
    function callHandler(handlerName, data, responseCallback) {
//沒有參數(shù)傳入 第二個參數(shù)為函數(shù)類型 的情況處理
        if (arguments.length == 2 && typeof data == 'function') {
            responseCallback = data;
            data = null;
        }
// 最終調(diào)用 將調(diào)用的 handlerName 和參數(shù) 包裝成字典 
        _doSend({ handlerName:handlerName, data:data }, responseCallback);
    }

3、改變iframe.src 屬性,觸發(fā)OC端代理方法

    function _doSend(message, responseCallback) {
//有回調(diào) 則生成唯一callbackId,并存在全局sendMessageQueue.push數(shù)組中。 
        if (responseCallback) {
            var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime();
//在注冊的方法真正執(zhí)行時才將回調(diào)函數(shù)存儲在全局 responseCallbacks 中
            responseCallbacks[callbackId] = responseCallback;
            message['callbackId'] = callbackId;
// 在傳入的字典中加入  callbackId  ,此時 message 應(yīng)為
 //{ handlerName:handlerName, data:data,callbackId:callbackId }
        }
        sendMessageQueue.push(message);
// 將此字典存入全局  數(shù)組 sendMessageQueue
        messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
    }

4、觸發(fā)代理

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (webView != _webView) { return; }
    NSURL *url = navigationAction.request.URL;
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;

    if ([_base isWebViewJavascriptBridgeURL:url]) {
        if ([_base isBridgeLoadedURL:url]) {// 初始化 注入js
            [_base injectJavascriptFile];
        } else if ([_base isQueueMessageURL:url]) {// 已經(jīng)完成js注入 進(jìn)入消息發(fā)送 
            [self WKFlushMessageQueue];
        } else {
            [_base logUnkownMessage:url];
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {
        [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
    } else {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}

4、獲取到callbackId

// 取出 js全局 sendMessageQueue 存的全部數(shù)據(jù)
- (NSString *)webViewJavascriptFetchQueyCommand {
    return @"WebViewJavascriptBridge._fetchQueue();";
}
//實際執(zhí)行
    function _fetchQueue() {
        var messageQueueString = JSON.stringify(sendMessageQueue);
        sendMessageQueue = [];
// 返回  callbackId 
        return messageQueueString;
    }
- (void)WKFlushMessageQueue {

    [_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) {
        if (error != nil) {
            NSLog(@"WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@", error);
        }
//拿到  callbackId 進(jìn)入 調(diào)用OC方法
        [_base flushMessageQueue:result];
    }];
}

5、核型方法 調(diào)用OC方法并回調(diào)

-(void)flushMessageQueue:(NSString *)messageQueueString{
    if (messageQueueString == nil || messageQueueString.length == 0) {
        NSLog(@"WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page.");
        return;
    }

    id messages = [self _deserializeMessageJSON:messageQueueString];
    for (WVJBMessage* message in messages) {
        if (![message isKindOfClass:[WVJBMessage class]]) {
            NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message);
            continue;
        }
        [self _log:@"RCVD" json:message];
  /*
    JS 調(diào)用OC 不走此流程
        NSString* responseId = message[@"responseId"];
        if (responseId) {
            WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
            responseCallback(message[@"responseData"]);
            [self.responseCallbacks removeObjectForKey:responseId];
        } else*/ {
          
            WVJBResponseCallback responseCallback = NULL;
            NSString* callbackId = message[@"callbackId"];
   // 有回調(diào)  callbackId 則生成一個  
//typedef void (^WVJBResponseCallback)(id responseData); 同類型的block
            if (callbackId) {
                responseCallback = ^(id responseData) {
                    if (responseData == nil) {
                        responseData = [NSNull null];
                    }
                    // 關(guān)鍵代碼 再次回傳 callbackId 并傳入回調(diào)參數(shù)
                    WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
                    [self _queueMessage:msg];
                };
            } else {
                responseCallback = ^(id ignoreResponseData) {
                    // Do nothing
                };
            }
            // 根據(jù)OC端注冊名 在全局字典 self.messageHandlers 中取出保存的block
            WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
            
            if (!handler) {
                NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
                continue;
            }
            // 執(zhí)行
            handler(message[@"data"], responseCallback);
// 因為 responseCallback 也是一個block 其中會執(zhí)行    [self _queueMessage:msg];   
        }
    }
}

6、核型方法 調(diào)用OC方法并回調(diào)

- (void)_dispatchMessage:(WVJBMessage*)message {
    NSString *messageJSON = [self _serializeMessage:message pretty:NO];
    [self _log:@"SEND" json:messageJSON];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"];
    
    NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON];
//在主線程中直接執(zhí)行js 傳入的參數(shù) 為 @{ @"responseId":callbackId, @"responseData":responseData };
    if ([[NSThread currentThread] isMainThread]) {
        [self _evaluateJavascript:javascriptCommand];

    } else {
        dispatch_sync(dispatch_get_main_queue(), ^{
            [self _evaluateJavascript:javascriptCommand];
        });
    }
}

7、調(diào)用回調(diào)

        function _doDispatchMessageFromObjC() {
            var message = JSON.parse(messageJSON);
            var messageHandler;
            var responseCallback;

            if (message.responseId) {
                responseCallback = responseCallbacks[message.responseId];
                if (!responseCallback) {
                    return;
                }
// 拿出步驟二存的回調(diào)函數(shù) 執(zhí)行
                responseCallback(message.responseData);
// 執(zhí)行完畢 刪除回調(diào)函數(shù)
                delete responseCallbacks[message.responseId];
            }
// 下面的不走 JS調(diào)用OC并回調(diào)的過程到此結(jié)束
/* else {
                if (message.callbackId) {
                    var callbackResponseId = message.callbackId;
                    responseCallback = function(responseData) {
                        _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData });
                    };
                }
                
                var handler = messageHandlers[message.handlerName];
                if (!handler) {
                    console.log("WebViewJavascriptBridge: WARNING: no handler for message from ObjC:", message);
                } else {
                    handler(message.data, responseCallback);
                }
            }
        }
*/
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容