美文网首页
iOS WKWebView的使用

iOS WKWebView的使用

作者: 隔墙送来秋千影 | 来源:发表于2019-10-16 15:38 被阅读0次

    原文:https://juejin.im/post/5da4363ef265da5bb065e357

    级别:★☆☆☆☆
    标签:「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效果。

    QiWKWebView1.gif

    <figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

    第二个效果图展示了WKWebView加载本地Html 文件,及相关加载新页面、弹出alert弹框、打开其他应用的内容。

    QiWKWebView2.gif

    <figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

    一、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中点击链接后加载新页面的方式有:

    <a href="http://www.so.com" rel="external nofollow" target="_self">self so.com</a>
    <a href="https://www.so.com" rel="external nofollow" target="_parent">parent so.com</a>
    <a href="https://www.so.com" rel="external nofollow" target="_top">top so.com</a>
    
    <a href="https://www.so.com" rel="external nofollow" target="_blank">blank 打开so.com</a>
    
    <a href="javascript:"  onClick="window.open('https://www.so.com',' ')">window 打开so.com</a>
    复制代码
    

    笔者把上边几种方式分为3类,使用href的方式打开的和使用js打开的html界面。

    使用href方式打开的界面就分为target="blank"的与其他。

    href方式打开新页面

    target="_blank"
    <a href="https://www.so.com" rel="external nofollow" target="_blank">blank 打开so.com</a>
    复制代码
    

    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打开新页面

    <a href="javascript:"  onClick="window.open('https://www.so.com',' ')">window 打开so.com</a>
    复制代码
    

    使用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页面跳转到其他应用的情况。

    比如说发邮件,发信息,打电话

    <a href="mailto:someone@example.com?cc=someoneelse@example.com&bcc=andsomeoneelse@example.com&subject=Summer%20Party&body=You%20are%20invited%20to%20a%20big%20summer%20party!" target="_top">发送邮件</a>
    <br>
    给<a href="sms:10086,10010?body=消息内容">10086,10010</a>发信息
    <br>
    给<a href="tel:10086">10086</a>打电话 
    复制代码
    

    这种情况我们的需要在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·HiOS与JS交互之WKWebView-WKUIDelegate协议

    笔者了解的弹框的方式有如下四种。笔者把下边下边的弹框分为2类,一类是使用js弹框,另一类是自定义的Toast。

    自定义Toast

    <script>
    //自定义弹框
    function Toast(msg,duration){
        duration=isNaN(duration)?3000:duration;
        var m = document.createElement('div');
        m.innerHTML = msg;
        m.style.cssText="width: 60%;min-width: 150px;opacity: 0.7;height: 200px;color: rgb(255, 255, 255);line-height: 100px;text-align: center;border-radius: 5px;position: fixed;top: 40%;left: 20%;z-index: 999999;background: rgb(0, 0, 0);font-size:48px;";
        document.body.appendChild(m);
        setTimeout(function() {
            var d = 0.5;
            m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
            m.style.opacity = '0';
            setTimeout(function() { document.body.removeChild(m) }, d * 1000);
        }, duration);
    }
    </script>
    复制代码
    

    像自定义的Toast弹框,WKWebView可以正常显示,不需要我们处理。

    js弹框

    <script>
    function alertFunction(){
        alert("你好,我是一个警告框!");
    }
    
    function confirmFunction(){
        window.confirm("confim 弹框");
    }
    
    function promptFunction(){
        window.prompt("prompt 弹框");
    }
    </script>
    复制代码
    

    像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

    参考学习网址

    相关文章

      网友评论

          本文标题:iOS WKWebView的使用

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