系列
一、前言
- 上一章我们讲述了通过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
最后
在新工作相对屌丝,相对安逸的情况下。希望自己能不忘初心,脚踏实地
网友评论