简单说明下WebViewJavascriptBridge执行流程
简单说明下WebViewJavascriptBridge执行流程
原理: 原理其实很好理解,主要就内置的webview,通过一个基类的信息存储,通过webview处理js中函数事件,以及基类中数据存储再执行,数据再封装成指定格式,来实现callbackID和responseID的实现;;并且js那边也有个jsbridge对象来处理之前约定的回调事件,如客户端定义的handler,也就是handlerName对应的回调函数在js对象中其实有一个对应的回调方法可以触发执行js的方法
介绍
WebViewJavascriptBridgeBase,一个存储类,用户消息记录,responseCallbackId记录以及messageHandler的记录,分别对应下面指定的属性定义1
2
3
4
5
6
7
8
9@property (assign) id <WebViewJavascriptBridgeBaseDelegate> delegate;
@property (strong, nonatomic) NSMutableArray* startupMessageQueue;
OC这边一个存储器,当我们开始从原生发送消息给webview时,
我们还不能确定我们需要添加的js文件已经加载完毕或者js中的bridge对象是否已经初始化成功,如果没有,则需要在这个存储的类开始存储消息;;
@property (strong, nonatomic) NSMutableDictionary* responseCallbacks;
OC中的回调函数的存储器,key为一次递增的uniqueID,value是传入的block的copy,用户后续指定的消息体返回时,OC模块代码的回调
@property (strong, nonatomic) NSMutableDictionary* messageHandlers;
存储约定的事件,跟js约定相同的事件,已经key来执行指定的block事件,区分于responseCallbacks的执行事件
@property (strong, nonatomic) WVJBHandler messageHandler;
主要罗列主要的方法,但由于三方库在不断更新,可能方法、实现以及调用方式都会修改
初始化webview
1 | + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView |
js代码块加载
1 | - (BOOL)webView:(UIWebView *)webView |
注册handler
注册的handler会存放在messagehandlers里面,handler是个block,后续直接执行handler就可以了
1 | - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { |
通过OC直接调用js函数
1 |
|
总结一下调用:分为3个模块,客户端代码调用事件,传入对应的data, responseCallBackID 事件处理之后,分为了handler的模块和responsecallbackID的模块,handler事件直接执行html中初始化函数的回调【函数回调是data和根据callbackID 新生成的responseID】,新生成的responseID需要通过iframe对象想客户端回传,进行url的触发,js在自己的sendMessageQueue中保存一份,通过flushMessageQueue来执行。
web页面执行OC里面的函数;
前端页面执行buttonClick事件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
callbackButton.innerHTML = 'Fire testObjcCallback'
callbackButton.onclick = function(e) {
e.preventDefault()
log('JS calling handler "testObjcCallback"')
bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
log('JS got response', response)
})
}
调用js中的实例对象
function callHandler(handlerName, data, responseCallback) {
_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
}
sendMessageQueue.push(message)
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE
}
返回给OC的webview去回调这个事件,然后在客户端内部实现对返回的message进行处理,通过_fetchQueue来获取message内部信息,解析封装成指定的responseID,将获取到最新的数据封装成指定格式,解析,最后再次通过_handleMessageFromObjC实现对应的结果
OC,webView(webview中分为html和js)的交互过程
解析一种相对复杂的交互模式
1 | //初始化部分 |
- 初始化webViewJavaScriptBridge:进行messageHandlers,startupMessageQueue,responseCallbacks等存储器以及_uniqueId等计数器的初始化;
- 加载本地的html文件,主要是针对html的script的对象进行初始化,详细看下setupWebViewJavascriptBridge(callback)函数,里面涉及了我们现在js的交互方式,通过iframe来重定向url(此处可以了解下这种方式比起window.location的优势是什么),【注意几个点,window.WVJBCallbacks = [callback]将块的匿名函数初始化给window.WVJBCallbacks,后续在js文件初始化之后,会依次初始化callback的内容;另外初始化中的log以及resgisterHandler的事件也注意下,后续在dosend的数据封装二次发送的时候需要用到】
- 通过回调给原生一个有效的scheme来使得客户端这里知道我们此时需要加载一段js代码,从而触发了injectJavascriptFile()函数调用,js必须全部加载完成并对应对象初始化完成,检测到相应的对象才有效,此时如果发送的消息会一次寄存在startupMessageQueue数组中,之前注册的testObjcCallback事件也会存放到messageHandlers的映射表中…初始化完成后,会对startupMessageQueue置空,便于后面的消息进行直接消费,同此同时存储在startupMessageQueue的消息也会立即消费
- 发送消息,不管是存放在startupMessageQueue中的消息还是立即会被消费的消息,都会先进行加工,所谓的加工就是将数据区分data,callbackId,handlerName,并在回调的responseCallbacks存储一份key为callbackId的block,用于后续的回调。
- WebViewJavascriptBridge._handleMessageFromObjC通过这段js代码将我们的消息发送到js端进行实现处理【注意要使用主线程来进行js代码处理】,解析,重新封装,再次使用js中的_dosend();[进行对responseId+responseData的数据封装];messageHandlers[message.handlerName];调用之前js初始化的匿名函数事件
- dosend的发送消息后,提示客户端有消息处理,并将当前的消息内容全部存储到js的bridge对象sendMessageQueue的存储器中,OC获取消息后,先通过js方法WebViewJavascriptBridge._fetchQueue()获取消息体,然后针对消息体的内容进行解析分析,回调对应事件
仓库地址链接:
https://github.com/marcuswestin/WebViewJavascriptBridge.git
优点:
- 在交互的过程中消息体一直通过js传参或者返回值来通信,规避通过iframe过于暴露消息结构体;
- 整体的设计思路还是很棒的
缺点:
- 理解起来还是有点复杂的,尤其是OC和JS交互过程的代码理解