iOS WKWebView的基本使用

級別:★☆☆☆☆
標籤:「WKWebView」「WKWebView加載新頁面失敗」「WKWebView 彈框沒有顯示」「WKWebView 打開其餘應用」
做者: WYW
審校: QiShare團隊
javascript


前言:
筆者最近了解了部分關於WKWebView的內容,將會在本文中說明關於WKWebView基本使用的內容。 WKWebView是一個展現交互式web內容的視圖,支持iOS8.0及macOS10.10以上的系統。php

本文涉及內容包括WKWebView展現Html、使用WKWebView時可能用到的API、WKWebView 加載新頁面、WKWebView正常顯示JS彈框、WKWebView截圖。css

筆者作了2個效果圖以下:html

第一個效果圖展現了WKWebView加載url,及相關返回、前進、從新加載、查看backForwardList中item信息、截圖等API效果。java

QiWKWebView1.gif

第二個效果圖展現了WKWebView加載本地Html 文件,及相關加載新頁面、彈出alert彈框、打開其餘應用的內容。git

QiWKWebView2.gif

1、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]]; */
複製代碼

2、WKWebView可能用到的API

allowsBackForwardNavigationGestures

容許左滑右滑,默認值爲NO;設置爲YES後,便可實現左右滑手勢可用。github

_webView.allowsBackForwardNavigationGestures = YES;web

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);
    }
}];
複製代碼

3、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);
        }
    }
}
複製代碼

4、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

參考學習網址


小編微信:可加並拉入《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(一)
奇舞週刊

相關文章
相關標籤/搜索