JavaScriptCore(适用于UIWebview,具有模块化思想)
JavaScriptCore库里主要包括JSContext、JSValue、JSExport等几个一般使用的就是列举的三个。关键有两步:获取js的运行上下文,将继承JSExport的模块注入js。JSContext是js的运行上下文,用来执行js代码;JSValue是JSContext执行后的返回结果,JSExport是用来将native对象暴漏给js。
- 从native调用js
jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext
jsContext.evaluateScript("var a = 1;")
jsContext?.objectForKeyedSubscript("jsMethod")
- 从js调用native函数
利用JSExport是一个协议,通过实现它可以完成把一个native对象暴漏给js,就可以用js来调用native
@objc protocol BridgeDelegate: JSExport {
func jsCallNative(_ arg: String)
}
WKScriptMessageHandler(适用于WKWebview,没有模块化思想)
WKScriptMessageHandler 是一个协议,这个协议提供一个方法可以接收 JS 传过来的消息,这个协议方法里面有两个类 WKScriptMessage(包含方法名以及参数) 和 WKUserContentController(调用方法)。
//可以理解为注册方法以便js调用
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
//用于接受js消息调用native方法
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
}
}
一个使用广泛的第三方轮子WebViewJavascriptBridge
简介:WebViewJavascriptBridge适用于UIWebview与WKWebview,他通过webview的代理拦截特定的scheme。
- 首先三重判断
//是否来自该库的消息
if ([_base isWebViewJavascriptBridgeURL:url]) {
//是否以及注入js
if ([_base isBridgeLoadedURL:url]) {
[_base injectJavascriptFile];
//是否是要处理的消息
} else if ([_base isQueueMessageURL:url]) {
[self WKFlushMessageQueue];
- 执行js获取消息字符串,剖析消息
- 通过messageHandlers来执行消息,利用callbackID来进行回掉
//设置回调
WVJBResponseCallback responseCallback = NULL;
NSString* callbackId = message[@"callbackId"];
if (callbackId) {
responseCallback = ^(id responseData) {
if (responseData == nil) {
responseData = [NULL];
}
WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
//执行js根据callbackId执行对应的回调
[self _queueMessage:msg];
};
}
//根据之前注册的处理函数进行处理
WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
if (!handler) {
NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
continue;
}
handler(message[@"data"], responseCallback);
里面还有很多细节,网上资料众多这里不进行赘述有问题可以留言一起探讨。总体来说就是WebViewJavascriptBridge是截获Webview的代理方法,执行js获取js调用native的消息再通过函数名称调用注册的函数。它的callbackid,注册的函数等是通过数组、字典保存起来了因此可以省去反射的步骤。整体还是比较繁琐没有模块化管理。
最后我们可以举一反三以下是我的一个列子
- 从native调用js直接使用
self.AS_WKWebview?.evaluateJavaScript(item, completionHandler: nil)
- 从js调用native函数
总体流程应该是这样的:
- 约定好规范,名称,模块
- native端注入js使得web端可以通过模块名加方法名发出讯号
- web发出讯号(常用的有alert、confirm、Prompt)
- native端拦截讯号判断是需要处理还是正常执行
- 对讯号进行解析判断模块名、方法名、参数合法性(包括回调函数)
- 利用反射执行方法、调用回调函数
- 自己还可以进行其他的处理比如白名单、权限处理
网友评论