WebViewJavascriptBridge 原理解析

栏目: JavaScript · 发布时间: 5年前

内容简介:WebViewJavascriptBridge是项目中常用的OC与js交互的第三方框架,它没有通过苹果的JavascriptCore框架来实现,而是实现了自己的逻辑。下面看一下Message的数据结构,当然在传送的过程中是一JSON的格式进行传送的,以OC为例:

WebViewJavascriptBridge是项目中常用的OC与js交互的第三方框架,它没有通过苹果的JavascriptCore框架来实现,而是实现了自己的逻辑。

WebViewJavascriptBridgeBase 是OC模块的功能实现类,对应的js功能类为 WebViewJavascriptBridge_JS ,此处巧妙地使用字符串来解决了之前版本集成打包需要bundle加载js模块的问题。

先说明几个数据结构:

  • @property (strong, nonatomic) NSMutableDictionary messageHandlers; ,以字典的形式保存注册的Hander,js相似数据结构为: var messageHandlers = {};
  • NSMutableDictionary* responseCallbacks; ,以字典的形式保存调用Handler后回调给js消息的Block,js相似数据结构为: var responseCallbacks = {};

下面看一下Message的数据结构,当然在传送的过程中是一JSON的格式进行传送的,以OC为例:

NSMutableDictionary* message = [NSMutableDictionary dictionary];
    if (data) {
        message[@"data"] = data;
    }
    if (responseCallback) {
        NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId];
        self.responseCallbacks[callbackId] = [responseCallback copy];
        message[@"callbackId"] = callbackId;
    }
    if (handlerName) {
        message[@"handlerName"] = handlerName;
    }
复制代码

data :要传递的数据(如参数)。

callbackId : 唯一标示作为responseCallBack的Key

handerName :Handler唯一标示(Key)

对应js代码:

_doSend({ handlerName:handlerName, data:data }, responseCallback);

function _doSend(message, responseCallback) {
	if (responseCallback) {
		var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime();
		responseCallbacks[callbackId] = responseCallback;
		message['callbackId'] = callbackId;
	}
复制代码

发送消息,OC为调用WebView调用 evaluateJavascript 方法来调用js,通过WebViewJavascriptBridge来调用js的 _handleMessageFromObjC方法 主要代码:

- (void)_dispatchMessage:(WVJBMessage*)message {
    NSString *messageJSON = [self _serializeMessage:message pretty:NO];
    [self _log:@"SEND" json:messageJSON];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
    <-------------省略-------------->
    
    NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON];
    if ([[NSThread currentThread] isMainThread]) {
        [self _evaluateJavascript:javascriptCommand];

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

而js调用OC则是通过WebView加载Request来实现:

function _doSend(message, responseCallback) {
		if (responseCallback) {
			var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime();
			responseCallbacks[callbackId] = responseCallback;
			message['callbackId'] = callbackId;
		}
		sendMessageQueue.push(message);
		messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
	}
复制代码
  1. 添加Message到待处理消息集合MessageQueue,然后调用 messagingIframe.src 来加载Request,格式为: https://__wvjb_queue_message__
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (webView != _webView) { return YES; }
    NSURL *url = [request URL];
    __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
    if ([_base isWebViewJavascriptBridgeURL:url]) {
        if ([_base isBridgeLoadedURL:url]) {
            [_base injectJavascriptFile];
        } else if ([_base isQueueMessageURL:url]) {
            NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
            [_base flushMessageQueue:messageQueueString];
        } else {
            [_base logUnkownMessage:url];
        }
        return NO;
    } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
        return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
    } else {
        return YES;
    }
}
复制代码

2.获取要处理的js消息,进行处理,先说一下代码里的判断函数

isWebViewJavascriptBridgeURL :判断是否是Bridge处理的URL格式,为了兼容旧版本,判断了2个Scheme,然后继续下面2个函数的判断。

isBridgeLoadedURL :判断是否是Bridge初始化加载URL格式,对应格式为: https://__bridge_loaded__ ,如果是,则调用injectJavascriptFile函数,加载初始化的js文件(WebViewJavascriptBridge_JS)

isQueueMessageURL :判断是否是Bridge发送消息的URL格式,对应格式为: https://__wvjb_queue_message__

当url是 https://__wvjb_queue_message__ ,则表示js有消息要处理,WebView加载Request,调用OC [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]] 这个方法来调用js文件中的

function _fetchQueue() {
		var messageQueueString = JSON.stringify(sendMessageQueue);
		sendMessageQueue = [];
		return messageQueueString;
	}
复制代码

方法,来获取要处理的消息,然后调用OC的 flushMessageQueue: 方法来处理消息

处理消息,OC处理js方法为 - (void)flushMessageQueue:(NSString *)messageQueueString{xxx}

先看这部分代码:

WVJBResponseCallback responseCallback = NULL;
            NSString* callbackId = message[@"callbackId"];
            if (callbackId) {
                responseCallback = ^(id responseData) {
                    if (responseData == nil) {
                        responseData = [NSNull null];
                    }
                    
                    WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
                    [self _queueMessage:msg];
                };
            } else {
                responseCallback = ^(id ignoreResponseData) {
                    // Do nothing
                };
            }
            
            WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
            
            if (!handler) {
                NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
                continue;
            }
            
            handler(message[@"data"], responseCallback);
复制代码

如果存在callbackId,则代表js存在responseCallBack,需要OC回调,所以需要发送回调消息即`WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; [self _queueMessage:msg];只是callbackId的KEY设置成responseId来区分是回调。 再看代码:

NSString* responseId = message[@"responseId"];
        if (responseId) {
            WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
            responseCallback(message[@"responseData"]);
            [self.responseCallbacks removeObjectForKey:responseId];
        }
复制代码

首先判断是否有responseId(即OC的ResponseCallBack保存时候的CallbackId),如果有,那么代表这个消息是js的回调消息(OC调用js注册的Handler),则直接处理。

如果我的文章对你有所帮助,请留言告诉我,Thanks!


以上所述就是小编给大家介绍的《WebViewJavascriptBridge 原理解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java算法

Java算法

塞奇威克 / 赵文进 / 清华大学出版社 / 2004-06-01 / 59.0

《Java算法》用Java语言全面实现了当今最重要的计算机算法,并用大量图表和数学公式对算法进行了详尽的描述和分析。全书共分3卷,本书是其中的第1卷(第1至第4部分)。内容包括基本概念(第1部分)、数据结构(第2部分)、排序算法(第3部分)和查找算法(第4部分)。本书概念清楚,内容翔实,新颖,由浅入深地描述了算法。本书可作为高等院校计算机相关专业本科生和研究生的教材和补充读物,也可作为Java爱好一起来看看 《Java算法》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码