现在的位置: 主页 > 公司荣誉 > 文章正文
WebViewJavascriptBridge 原理分析
作者:吴桥县齐源纤维素有限公司 来源:www.qy-xws.com 发布时间:2017-09-10 10:00:02
WebViewJavascriptBridge 原理分析

网上好多都是在介绍 WebViewJavascriptBridge如何使用,这篇文章就来说说 WebViewJavascriptBridge 设计原理。

主要从两个过程来讲一下:js调用UIViewController中的代码(Native),Native调用js

1.概述

首先有两个问题:

a.Native(中的UIWebView)是否可以直接调用js method(方法)? 可以。

b.js 是否可以直接调用Native的mthod?不行。

明确上述两个问题,那么上图就不难明白了,webpage中的js method和webview本地的method之间关系。那WebViewJavascriptBridge出现是否解决这个问题(这个问题就是让js可以直接调用native的method)呢?答案是否定的?没有本质还是用uiwebview的代理方法进行字段拦截(判断url的scheme),实现js间接调用native的method。

我们来看WebViewJavascriptBridge提供的demo:

主要的核心是下面两个,接下来我们就来讨论一下其设计原理。

2.js调用Native method

在概述中说过,js是不能直接调用native的method所以,需要借助- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType,这个方法大家不陌生,每次在重新定向URL的时候,这个方法就会被触发,通常情况,我们会在这里做一些拦截完成js和本地的间接交互什么的。那么WebViewJavascriptBridge也不另外,也是这么做。

我们先来看看在ExampleApp.html文件中点击一个按钮发起请求的代码:

var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button')) callbackButton.innerHTML = 'Fire testObjcCallback' callbackButton.onclick = function(e) { e.preventDefault() log('JS calling handler "testObjcCallback"') //1 bridge.callHandler('testObjcCallback', {'foo': 'cccccccccccc'}, function(response) { log('JS got response', response) }) }
估计大家大体都能看懂,唯独有疑问的地方是:

bridge.callHandler('testObjcCallback', {'foo': 'cccccccccccc'}, function(response) { log('JS got response', response) }) }
这段代码先不说,上面代码就是一个按钮的普通单击事件方法。我们一起想一下,如果这个按钮需要被点击之后调用native中的funtion函数,之后需要把这个(native的)funtion函数处理结果返回给js中的方法继续处理。这个是我们需求,带着这个需求我们看一下这个方法,testObjcCallBack这个我们猜测一下应该native中的方法或者一个能够调用到方法的name/id,后面这个是个json{‘foo’:‘ccccccccccccc’},应该是个参数,那么后面这个方法一看log应该知道,是对native返回的result进行处理的方法。拿具体是不是呢?只要找到callHandler方法就知道了。

在文件WebViewJavascriptBridge.js.txt里面我们找找这个方法:

function callHandler(handlerName, data, responseCallback) { _doSend({ handlerName:handlerName, data:data }, responseCallback) }
这里又多了一个方法叫_doSend连个参数 第1个是字典key-value定义,第二个是一个方法的指针(看看上面的方法你就知道了),那我们必须在同一个文件里面看看能不能找到这个_doSend方法:

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 }
找到了。

逐行分析一下,变量callbackId是个字符串,responseCallBacks[] 一看就知道是个字典 ,这个字典把回掉(我们猜测)的方法responseCallback给保存起来,这Key(也就是callbackId)应该是唯一的,通过计数和时间应该知道这个字符串应该是唯一的,message也是一个字典,这是给message添加了一个新的key-value。干嘛呢?我也不知道,我们来看看sendMessageQueue是什么,大家一个push就知道应该是个数组。他吧一个字典放到一个消息队列中(数组队列),让后产生一个src(url scheme)。

有两个变量我们看看:

var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme' var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'

干嘛用,肯定是给webview 的 delegate判断用的,你感觉呢?(肯定是)

下面是在文件:WebViewJavascriptBridge.m

好了到了这里大家猜猜这个要干嘛?肯定是要发url让web截取对吧?那还用问啊,肯定是啊,已经说过了js能不能调用native的funtion函数?不能。我们来看看这个messagingIframe是:

function _createQueueReadyIframe(doc) { messagingIframe = doc.createElement('iframe') messagingIframe.style.display = 'none' messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE doc.documentElement.appendChild(messagingIframe) }
原来就是iframe,这个就不同给大家解释了。好了src一产生就会出现什么,uiwebview代理回掉截获,采集软件,此时我们把目光回到UIWebview的Native下面:

- (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 ([[url scheme] isEqualToString:kCustomProtocolScheme]) { if ([[url host] isEqualToString:kQueueHasMessage]) { //会走这里 [self _flushMessageQueue]; } else { NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); } return NO; } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; } else { return YES; } }
一看就头大,哈哈,是,我也头大。看看上面的注释说 会走这里,我们看看为什么会走那里,最外圈的if([url scheme])判断是

#define kCustomProtocolScheme @"wvjbscheme"

这个定义是什么意思,我们先不做解释,刚才我们说过js不能直接调用native的function,大家只要记住这点,接着往下走就是了。至于为什么走这里,自己看代码(上文有提到),我们看看_flushMessageQueue:

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:襄阳SEO http://xiangyang.raoyu.net


  • 上一篇:分享几点写原创文章的思路
  • 下一篇:最后一页
  • 
    COPYRIGHT © 2015 吴桥县齐源纤维素有限公司 ALL RIGHTS RESERVED.
    本站所有原创信息,未经许可请勿任意转载或复制使用 网站地图 技术支持:肥猫科技
    精彩专题:网站建设
    购买本站友情链接、项目合作请联系客服QQ:2500-38-100