使用WKWebView的时候,如果想要实现JS调用OC方法,除了拦截URL之外,还有一种简单的方式。那就是利用WKWebView的新特性MessageHandler来实现JS调用原生方法。
MessageHandler 是什么?
WKWebView 初始化时,有一个参数叫configuration,它是WKWebViewConfiguration类型的参数,而WKWebViewConfiguration有一个属性叫userContentController,它又是WKUserContentController类型的参数。WKUserContentController对象有一个方法- addScriptMessageHandler:name:,我把这个功能简称为MessageHandler。
- addScriptMessageHandler:name:有两个参数,第一个参数是userContentController的代理对象,第二个参数是JS里发送postMessage的对象。 所以要使用MessageHandler功能,就必须要实现WKScriptMessageHandler协议。 我们在该API的描述里可以看到在JS中的使用方法:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
//其中<name>,就是上面方法里的第二个参数`name`。
//例如我们调用API的时候第二个参数填@"Share",那么在JS里就是:
//window.webkit.messageHandlers.Share.postMessage(<messageBody>)
//<messageBody>是一个键值对,键是body,值可以有多种类型的参数。
// 在`WKScriptMessageHandler`协议中,我们可以看到mssage是`WKScriptMessage`类型,有一个属性叫body。
// 而注释里写明了body 的类型:
Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.
MessageHandler的使用
// 这是创建configuration 的过程
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 40.0;
configuration.preferences = preferences;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// addScriptMessageHandler 很容易导致循环引用
// 控制器 强引用了WKWebView,WKWebView copy(强引用了)configuration, configuration copy (强引用了)userContentController
// userContentController 强引用了 self (控制器)
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"GoBack"];
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"];
}
//需要注意的是addScriptMessageHandler很容易引起循环引用,导致控制器无法被释放,所以需要加入以下这段:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 因此这里要记得移除handlers
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Shake"];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"GoBack"];
}
WKScriptMessageHandler的代理实现
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
if ([message.name isEqualToString:@"Shake"]) {
NSLog(@"分享");
} else if ([message.name isEqualToString:@"GoBack"]) {
NSLog(@"返回");
}
}
JS调iOS原生方法
const u = navigator.userAgent;
//android终端
const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
// IOS终端
const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isiOS) {<!-- -->
window.webkit.messageHandlers.GoBack.postMessage('');//getUserId.postMessage('')为IOS定义的原生方法
//你的逻辑代码
} else if (isAndroid) {<!-- -->
window.java_obj.GoBack() //java_obj.getUserId()为安卓定义的方法,具体方法名可与其沟通
// 你的逻辑代码
}
网友评论