美文网首页混合开发
原生JS交互(二)—— WKWebView拦截URL

原生JS交互(二)—— WKWebView拦截URL

作者: CoderXLL | 来源:发表于2018-05-31 18:05 被阅读1099次

    系列

    原生JS交互(一)—— UIWebView拦截URL

    一、前言

    • 上一章我们讲述了通过UIWebView拦截URL,以及调用JS的Function,在原生方面与JS方面的实现。
    • 本章我们说一下WKWebView拦截URL在原生方面的实现。

    UIWebView与WKWebView比较
    1. 因为UIWebView会导致内存问题,所以建议开发者还是使用WKWebView加载H5页面
    2. 同时WKWebView可以很容易地实现H5页面加载进度
    3. WKWebView不能弹出前端的alert,需在代理方法中弹出原生alertController

    • 无论是WKWebView还是UIWebView,通过拦截URL的方式实现JS交互,JS的实现都是一样的原理,所以本章就不说了。
    • 先再贴一下上章的前端代码,与上一章的前端代码完全一致。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>拦截url</title>
        <script language="javascript">
            function loadURL(url) {
                var iFrame;
                iFrame = document.createElement("iframe");
                iFrame.setAttribute("src", url);
                iFrame.setAttribute("style", "display:none;");
                iFrame.setAttribute("height", "0px");
                iFrame.setAttribute("width", "0px");
                iFrame.setAttribute("frameborder", "0");
                document.body.appendChild(iFrame);
                // 发起请求后这个iFrame就没用了,所以把它从dom上移除掉
                iFrame.parentNode.removeChild(iFrame);
                iFrame = null;
            }
            /*拦截function*/
            function testBtnClick() {
                loadURL('mamami://click')
            }
        </script>
    
    </head>
    <body>
    <button onclick="testBtnClick()">移动端拦截</button>
    </body>
    </html>
    

    二、WKWebView加载HTML

    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = [[WKUserContentController alloc] init];
    WKPreferences *preferences = [[WKPreferences alloc] init];
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    preferences.minimumFontSize = 30.0;
    configuration.preferences = preferences;
    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    [self.view addSubview:webView];
    self.webView = webView;
    

    三、WKWebView的UIDelegate与navigationDelegate

    • UIDelegate,即WKUIDelegate协议代理对象。
      常用的协议方法如下:
    // webView关闭调用
    - (void)webViewDidClose:(WKWebView *)webView
    {
        
    }
    
    // WKWebView不能弹出alert,需要用原生alertController,其中message参数就是前端alert function中的参数
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
    {
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"哈哈" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"NO" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }];
        [alertVC addAction:cancelAction];
        [self presentViewController:alertVC animated:YES completion:nil];
    }
    
    • navigationDelegate,即WKNavigationDelegate协议代理对象。
      我们常用的协议方法如下:
    // 类似于UIWebView中拦截URL的代理方法,要注意的是decisionHandler不能连续回调两次,否则会引起crash
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
    {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    
    // H5页面开始加载回调方法
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
    {
        
    }
    
    // H5页面正在加载回调方法
    - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
    {
        
    }
    
    // H5页面结束加载回调方法
    - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
    {
        
    }
    
    // H5页面加载失败回调方法
    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    {
        
    }
    

    四、WKWebView监听前端页面加载进度

    使用KVO,监听WKWebView对象的estimatedProgress属性

    // KVO设置observer
    [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    
    // 监听回执
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
    {
        if ([object isEqual:self] && [keyPath isEqualToString:@"webView.estimatedProgress"])
        {
            [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
            if (self.progressView.progress == 1.0)
            {
                 self.progressView.hidden = YES;
            }
        }
    }
    

    五、WKWebView拦截URL

    使用上面已经提到的WKNavigationDelegate的协议方法。

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
    {
        NSString *urlStr = navigationAction.request.URL.absoluteString;
        if ([urlStr rangeOfString:@"mamami://click"].length > 0)
        {
            decisionHandler(WKNavigationActionPolicyCancel);
        } else {
            decisionHandler(WKNavigationActionPolicyAllow);
        }
    }
    

    六、WKWebView调用JS

    再次提醒前端,原生需要调用的function写在window下,别那么自信全局function与window下的function没有区别。

    NSString *jsStr = [NSString stringWithFormat:@"ocInvoke('%@','%@')", @"我", @"是"];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable data, NSError * _Nullable error) {
         NSLog(@"%@-%@", data, error);
    }];
    

    要注意一点,如果js调用了系统的alert function,原生使用WKWebView加载时,必须实现runJavaScriptAlertPanelWithMessage 协议方法,使用原生alertController进行弹窗。否则会造成crash

    最后

    在新工作相对屌丝,相对安逸的情况下。希望自己能不忘初心,脚踏实地

    相关文章

      网友评论

        本文标题:原生JS交互(二)—— WKWebView拦截URL

        本文链接:https://www.haomeiwen.com/subject/fjxcsftx.html