级别:★☆☆☆☆
标签:「WKWebView」「WKWebView加载新页面失败」「WKWebView 弹框没有显示」「WKWebView 打开其他应用」
作者: WYW
审校: QiShare团队
前言:
笔者最近了解了部分关于WKWebView的内容,将会在本文中说明关于WKWebView基本使用的内容。
WKWebView是一个展示交互式web内容的视图,支持iOS8.0及macOS10.10以上的系统。
本文涉及内容包括WKWebView展示Html、使用WKWebView时可能用到的API、WKWebView 加载新页面、WKWebView正常显示JS弹框、WKWebView截图。
笔者做了2个效果图如下:
第一个效果图展示了WKWebView加载url,及相关返回、前进、重新加载、查看backForwardList中item信息、截图等API效果。
第二个效果图展示了WKWebView加载本地Html 文件,及相关加载新页面、弹出alert弹框、打开其他应用的内容。
一、WKWebView加载html
加载网络url
WKWebViewConfiguration *webConfiguration = [WKWebViewConfiguration new];
_webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:webConfiguration];
NSString *urlStr = @"https://www.so.com";
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[_webView loadRequest:request];
加载本地html
WKWebViewConfiguration *webConfig = [WKWebViewConfiguration new];
webConfig.dataDetectorTypes = WKDataDetectorTypePhoneNumber;
_webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webConfig];
_webView.allowsBackForwardNavigationGestures = YES;
_webView.backgroundColor = [UIColor whiteColor];
self.view = _webView;
[_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiLink" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]];
/* // 或者使用如下方式
NSString *localHtmlStr = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"QiLink" ofType:@"html"] encoding:NSUTF8StringEncoding error:nil];
[_webView loadHTMLString:localHtmlStr baseURL:[[NSBundle mainBundle] bundleURL]];
*/
二、WKWebView可能用到的API
allowsBackForwardNavigationGestures
允许左滑右滑,默认值为NO;设置为YES后,即可实现左右滑手势可用。
_webView.allowsBackForwardNavigationGestures = YES;
goForward
goForward可以向前导航到back-forward列表中的内容,相当于回到关闭的之前看过的详情界面。
if ([_webView canGoForward]) {
[_webView goForward];
}
goBack
goBack可以向后导航到back-forward列表中的内容,相当于返回。
if ([_webView canGoBack]) {
[_webView goBack];
}
backForwardList
WKWebView的backForwardList,这里可以列表中条目的标题及url等信息。
if (_webView.backForwardList.forwardList.count > 0) {
NSLog(@"forwardItem");
NSLog(@"title:%@", _webView.backForwardList.forwardItem.title);
NSLog(@"URL:%@", _webView.backForwardList.forwardItem.URL);
}
if (_webView.backForwardList.backList.count > 0) {
NSLog(@"backwardItem");
NSLog(@"title:%@", _webView.backForwardList.backItem.title);
NSLog(@"URL:%@", _webView.backForwardList.backItem.URL);
}
reload
如出现Html内容未正常显示的问题,可用[_webView reload];
刷新WKWebView,重新加载Html的内容。
截图takeSnapshotWithConfiguration
如需截取当前显示在屏幕中的WKWebView的图片,可以使用
WKSnapshotConfiguration *snapConfig = [[WKSnapshotConfiguration alloc] init];
[_webView takeSnapshotWithConfiguration:snapConfig completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) {
if (!error) {
NSLog(@"%@", snapshotImage);
UIImageWriteToSavedPhotosAlbum(snapshotImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
} else {
NSLog(@"error:%@", error);
}
}];
三、WKWebView 加载新页面
笔者了解的实现Html中点击链接后加载新页面的方式有:
self so.com
parent so.com
top so.com
blank 打开so.com
window 打开so.com
笔者把上边几种方式分为3类,使用href的方式打开的和使用js打开的html界面。
使用href方式打开的界面就分为target="blank"
的与其他。
href方式打开新页面
target="_blank"
blank 打开so.com
target="_blank"相当于在新标签页打开一个新页面,需要在WKWebView的WKNavigationDelegate代理方法中处理导航切换的loadRequest请求。
#pragma mark - WKUIDelegate
// Decides whether to allow or cancel a navigation.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSLog(@"%@", webView.URL);
NSLog(@"%@", navigationAction.request.URL);
NSURL *url = navigationAction.request.URL;
if ([url.absoluteString hasPrefix:@"http"]) {
// The target frame, or nil if this is a new window navigation.
if (!navigationAction.targetFrame) {
[webView loadRequest:navigationAction.request];
}
decisionHandler(WKNavigationActionPolicyAllow);
} else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
target非"_blank"
target非"_blank"相当于在当前页面加载新的url,WKWebView可以可以正常加载url。
js打开新页面
window 打开so.com
使用js的window.open打开新页面,需要在WKWebView的UIDelegate代理方法中处理导航切换的loadRequest请求。
#pragma mark - WKUIDelegate
// creates a new web view.
// The web view returned must be created with the specified configuration. WebKit loads the request in the returned web view.
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
if (!navigationAction.targetFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}
打开其他应用
除了上述加载新页面的2种方式,还有一种从Html页面跳转到其他应用的情况。
比如说发邮件,发信息,打电话
发送邮件
给10086,10010发信息
给10086打电话
这种情况我们的需要在WKWebView的WKNavigationDelegate代理方法中处理应用跳转。
// Decides whether to allow or cancel a navigation.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly: @(NO)} completionHandler:^(BOOL success) {
// 成功调起三方App之后
NSLog(@"success:%@", @(success));
}];
decisionHandler(WKNavigationActionPolicyCancel);
} else {
// was called more than once'
decisionHandler(WKNavigationActionPolicyCancel);
}
}
综上,我们在使用WKWebView加载新页面的时候可能用到如下代码
// Decides whether to allow or cancel a navigation.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
if ([url.absoluteString hasPrefix:@"http"]) {
// The target frame, or nil if this is a new window navigation.
if (!navigationAction.targetFrame) {
[webView loadRequest:navigationAction.request];
}
decisionHandler(WKNavigationActionPolicyAllow);
} else if ([url.absoluteString hasPrefix:@"file://"]) {
// 加载本地文件
if (!navigationAction.targetFrame) {
[webView loadRequest:navigationAction.request];
}
decisionHandler(WKNavigationActionPolicyAllow);
} else {
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly: @(NO)} completionHandler:^(BOOL success) {
// 成功调起三方App之后
NSLog(@"success:%@", @(success));
}];
decisionHandler(WKNavigationActionPolicyCancel);
} else {
// was called more than once'
decisionHandler(WKNavigationActionPolicyCancel);
}
}
}
四、WKWebView显示JS弹框
相关内容涉及OC及JS之间的交互,详情请查看 Xs·H 的 iOS与JS交互之WKWebView-WKUIDelegate协议。
笔者了解的弹框的方式有如下四种。笔者把下边下边的弹框分为2类,一类是使用js弹框,另一类是自定义的Toast。
自定义Toast
像自定义的Toast弹框,WKWebView可以正常显示,不需要我们处理。
js弹框
像js弹框,WKWebView无法显示js弹框。我们需要利用js和OC的交互在WKWebView的WKNavigationDelegate的方法中分别做如下处理。
//! Alert弹框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ? : @"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * action = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
}
//! Confirm弹框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ?: @"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}];
[alertController addAction:confirmAction];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
//! prompt弹框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.text = defaultText;
}];
UIAlertAction * action = [UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alertController.textFields[0].text ? : @"");
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
}
Demo
相关代码见Demo:QiWKWebView
参考学习网址
- https://www.jianshu.com/p/7a1fceae5880
- https://www.runoob.com/html/html-links.html
- https://www.runoob.com/js/js-popup.html
- https://www.w3school.com.cn/tags/att_a_target.asp
- https://cloud.tencent.com/developer/article/1156176
- https://zhuanlan.zhihu.com/p/27457287
- https://blog.csdn.net/coslay/article/details/47446335
了解更多iOS及相关新技术,请关注我们的公众号:
小编微信:可加并拉入《QiShare技术交流群》。
关注我们的途径有:
QiShare()
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)
推荐文章:
Swift 5.1 (4) - 集合类型
iOS 解析一个自定义协议
iOS13 DarkMode适配(二)
iOS13 DarkMode适配(一)
2019苹果秋季新品发布会速览
申请苹果开发者账号的流程
Sign In With Apple(一)
奇舞周刊