博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WKWebView使用之MessageHandler
阅读量:5087 次
发布时间:2019-06-13

本文共 6245 字,大约阅读时间需要 20 分钟。

 使用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.
.postMessage(
)//其中
,就是上面方法里的第二个参数`name`。//例如我们调用API的时候第二个参数填@"Share",那么在JS里就是://window.webkit.messageHandlers.Share.postMessage(
)//
是一个键值对,键是body,值可以有多种类型的参数。// 在`WKScriptMessageHandler`协议中,我们可以看到mssage是`WKScriptMessage`类型,有一个属性叫body。// 而注释里写明了body 的类型:Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.

怎么使用MessageHandler?

1.创建WKWebViewConfiguration对象,配置各个API对应的MessageHandler。

WKUserContentController对象可以添加多个scriptMessageHandler。
// 这是创建configuration 的过程    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];    WKPreferences *preferences = [WKPreferences new];    preferences.javaScriptCanOpenWindowsAutomatically = YES;    preferences.minimumFontSize = 40.0;    configuration.preferences = preferences;
- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    self.webView.UIDelegate = self;    self.webView.navigationDelegate = self;    NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];    NSURL *url = [NSURL fileURLWithPath:path]; // [NSURL URLWithString:@"http://www.baidu.com"]; //        NSURLRequest *request = [NSURLRequest requestWithURL:url];    [self.webView loadRequest:request];    // addScriptMessageHandler 很容易导致循环引用    // 控制器 强引用了WKWebView,WKWebView copy(强引用了)configuration, configuration copy (强引用了)userContentController    // userContentController 强引用了 self (控制器)    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"clickYou"];    }

需要注意的是addScriptMessageHandler很容易引起循环引用,导致控制器无法被释放,所以需要加入以下这段:

- (void)viewWillDisappear:(BOOL)animated{    [super viewWillDisappear:animated];        // 因此这里要记得移除handlers    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"clickYou"];}

 

2.实现协议方法。

我这里实现了两个协议<WKUIDelegate,WKScriptMessageHandler>WKUIDelegate是因为我在JS中弹出了alert 。WKScriptMessageHandler是因为我们要处理JS调用OC方法的请求。

先看实现协议方法的示例代码:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{    NSLog(@"%@:%@",message.name,message.body);    if([message.name isEqualToString:@"clickYou"]){        [self clickYou];    }}

WKScriptMessage有两个关键属性name 和 body

因为我们给每一个OC 方法取了一个name,那么我们就可以根据name 来区分执行不同的方法。body 中存着JS 要给OC 传的参数。

3.处理HTML中JS调用。

function btnClick(){    //JS调用    window.webkit.messageHandlers.clickYou.postMessage({ "Acer": 500, "Dell": 600 });    alert(1);}

注意其中的clickYou,根据OC中注册的name一样.

 

4.OC调用JS

NSString *title = @"主题";    NSString *content = @"内容";    NSString *url = @"http://www.baidu.com";    NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {            }];
function shareResult(title,content,url){    alert("title:"+title+"content:"+content+"url:"+url);}

 

5.实现WKUIDelegate

如果JS中需要alert,那么实现WKUIDelegate三个代理方法,如下:

// alert框/** alert框 @param webView WKWebView @param message 消息文本内容 @param frame frame主窗口 @param completionHandler 窗口消失回调 */- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{    kFunLog    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];    [alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler();    }])];    [self presentViewController:alertController animated:YES completion:nil];}// 确认框- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{    kFunLog    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];    [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {        completionHandler(NO);    }])];    [alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler(YES);    }])];    [self presentViewController:alertController animated:YES completion:nil];}// 文本输入框- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{    kFunLog    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {        textField.text = defaultText;    }];    [alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler(alertController.textFields[0].text?:@"");    }])];        [self presentViewController:alertController animated:YES completion:nil];}- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo API_AVAILABLE(ios(10.0)){    return YES;}

 

转载于:https://www.cnblogs.com/HJiang/p/7832447.html

你可能感兴趣的文章
CPU,寄存器,一缓二缓.... RAM ROM 外部存储器等简介
查看>>
git .gitignore 文件不起作用
查看>>
Alan Turing的纪录片观后感
查看>>
c#自定义控件中的事件处理
查看>>
IOS--沙盒机制
查看>>
使用 JointCode.Shuttle 访问任意 AppDomain 的服务
查看>>
sqlite的坑
查看>>
digitalocean --- How To Install Apache Tomcat 8 on Ubuntu 16.04
查看>>
【题解】[P4178 Tree]
查看>>
Mongo自动备份
查看>>
cer证书签名验证
查看>>
synchronized
查看>>
【深度学习】caffe 中的一些参数介绍
查看>>
Python-Web框架的本质
查看>>
QML学习笔记之一
查看>>
App右上角数字
查看>>
从.NET中委托写法的演变谈开去(上):委托与匿名方法
查看>>
小算法
查看>>
201521123024 《java程序设计》 第12周学习总结
查看>>
新作《ASP.NET MVC 5框架揭秘》正式出版
查看>>