JS Call OC
首先,需要在OC中注册 JS 方法
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"testObjcCallback called: %@", data); responseCallback(@"Response from testObjcCallback"); }];复制代码
其中testObjcCallback就是JS调用OC方法 OC中在初始化的时候,需要注册相关的JS方法。这样OC这样就保留了一份以JS函数名字的信息(handlerName)。当JS调用OC的时候,会把JS自己的handlerName和data数据还有OC调用之后回调的block,一起传给JS工具类(callHandler方法可以选择传data数据)。JS工具类中callHandler函数会把handlerName和data数据封装成一个 message类型的字典,然后调用_doSend方法。_doSend方法会根据responseCallback的有无来判断 JS Call OC 后需不需要回调。如果需要回调的话JS应该把回调的responseCallback传递过来,JS工具类会通过全局的sendMessageQueue数组来保存发送的message信息。然后,改变 iframe 的 src 从而达到刷新WebView的作用。
WKWebView
调用
- (void)webView:(WKWebView *)webViewdecidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;复制代码
UIWebView
调用
- (BOOL)webView:(UIWebView *)webViewshouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType复制代码
OC会在上面的方法中拦截,由于JS提前和OC约定什么样的URL属于交互,所以当OC拦截到相关的方法时,会调用JS方法拿到 当前的 message,同时OC会通过handlerName去检测这个方法有没有在OC中注册。如果找到,那么回调这个block把JS的参数传递过去,并把OC回传的参数,再次和JS传递过来的 callbackId 组成一个字典(注:这里会把callbackId的key换成responseId),通过OC 执行JS _handleMessageFromObjC方法,JS会根据回传的responseId去全局数组responseCallback里面拿到回传的block,调用后,删除。 至此,整个 JS Call OC 流程结束。
总结如下:
- OC 需要提前注册 JS 方法,以便能够响应JS的调用,他们直接通过handlerName来关联
- JS 调 OC 是 设置 callbackId 参数和 需要传递的 data数据,保存在一个全局的消息数组中,然后通过OC拿到所有的消息,分别解析执行。而JS的回调是在OC中把当前的callbackId的key替换成responseId。
- JS 会把 responseCallback(JS的回调block)放进一个全局的字典中,以callbackId为键值,会把产生的消息放进sendMessageQueue数组中
- OC回调JS,作为JS调用OC完成的标志,JS会去responseCallbacks中取出,调用后删除。
OC Call JS
刚好实现流程反了过来,这时JS需要注册OC的方法,OC通过 UIWebView:
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;复制代码
或者 WKWebView
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;复制代码
来调用 JS 中_handleMessageFromObjC中的方法,把相关的参数一起带上,JS解析OC传过来的字段通过 判断 responseId 的有无来判断是call还是reponse(回应),并从messageHandlers取出提前注册的JS方法中的block,回应之后在通过改变iframe src的形式,同时把callbackId改成responseId回传给OC,OC拦截到之后,在去比较执行,在响应。 整体流程图如下: