相关文章推荐
安静的黄豆  ·  pymol 翻转180 - CSDN文库·  2 月前    · 
无聊的槟榔  ·  在 Exchange Server ...·  2 月前    · 
年轻有为的弓箭  ·  Application Error ...·  7 月前    · 
帅气的电影票  ·  mongoDB ...·  1 年前    · 
痴情的墨镜  ·  flatbuffers vs ...·  1 年前    · 
笔者最近了解了部分关于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中点击链接后加载新页面的方式有:

<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><a href="sms:10086,10010?body=消息内容">10086,10010</a>发信息
给<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·H iOS与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可以正常显示,不需要我们处理。

<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: QiWKWebView

参考学习网址

  • www.jianshu.com/p/7a1fceae5…
  • www.runoob.com/html/html-l…
  • www.runoob.com/js/js-popup…
  • www.w3school.com.cn/tags/att_a_…
  • cloud.tencent.com/developer/a…
  • zhuanlan.zhihu.com/p/27457287
  • blog.csdn.net/coslay/arti…
  • 了解更多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(一)
    且行且珍惜_iOS

    私信
    5,764