混合开发

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

2018-05-31  本文已影响1099人  CoderXLL

系列

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

一、前言

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

<!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

// 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];
}
// 类似于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

最后

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

上一篇 下一篇

猜你喜欢

热点阅读