zoukankan      html  css  js  c++  java
  • WKWebView使用之MessageHandler

     使用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?

    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;
    }
  • 相关阅读:
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之多方式虚拟直播
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之点播分享
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器与EasyDSS流媒体解决方案的不同
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器软件实现的多码率视频点播功能说明
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之Windows服务安装
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之Nodejs调用bat或sh脚本
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之Grunt的使用简介
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器启用https服务申请免费证书
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器软件二次开发接口对接说明示列
    EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器和EasyDSS云平台异同
  • 原文地址:https://www.cnblogs.com/HJiang/p/7832447.html
Copyright © 2011-2022 走看看