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; } 复制代码
-
添加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 原理解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
RGB转16进制工具
RGB HEX 互转工具
URL 编码/解码
URL 编码/解码