WKWebView API

WKWebView 对象可以显示交互式Web内容,例如应用内浏览器。你可以使用 WKWebView 类将Web内容嵌入到你的应用程序中。 为此,创建一个 WKWebView 对象,像设置视图一样设置它,并向其发送加载Web内容的请求。

预览

重要

从 iOS 8.0 和 OS X 10.10 开始,在你的APP中使用 WKWebView 添加网页内容,不要使用 UIWebViewWebView

使用 initWithFrame:configuration: 方法创建了一个新的 WKWebView 对象之后,你需要加载web内容。使用 loadHTMLString:baseURL: 方法加载本地 HTML 文件或者使用 loadRequest: 方法开始加载 web 内容。使用 stopLoading 方法停止加载,并且使用 loading 属性查看 web 视图是否正在加载中。为对象设置委托属性以遵守 WKUIDelegate 协议,以跟踪Web内容的加载。

要允许用户在 web 历史页面中前进或者后退,为按钮设置使用 goBackgoForward方法的动作。当用户不能在某个方向上再移动时,使用canGoBackcanGoForward属性禁用按钮。

默认情况下,web 视图会自动将出现在 web 内容中的电话号码转换为电话链接。当电话链接被点击时,电话应用程序就会启动并拨打该号码。要关闭这个默认的行为,用 WKDataDetectorTypes 设置 dataDetectorTypes 属性以不包含 WKDataDetectorTypePhoneNumber 标志。

你还可以使用 setMagnification:centeredAtPoint: 以编程方式设置Web内容第一次在Web视图中显示的缩放比例。 此后,用户可以使用手势来改变比例。

Symbols

初始化web视图

  • configuration
    用于初始化Web视图的配置副本。
  • - initWithFrame:configuration:
    用指定的 frame 和 configuration 初始化web视图 。
  • - initWithCoder:

查看web信息

  • scrollView
    与web视图相关联的滚动视图。
  • title
    页面标题。
  • URL
    活动网址。
  • customUserAgent
    自定义用户代理字符串。
  • serverTrust
    用于当前待导航的 SecTrustRef 对象。

设置委托

  • navigationDelegate
    web视图的导航代理。
  • UIDelegate
    web视图的用户界面委托。

加载内容

  • estimatedProgress
    当前导航的哪几个部分已经加载的估计值(double:0.0~1.0)。
  • hasOnlySecureContent
    布尔值,指示页面上的所有资源是否通过安全加密的连接加载。
  • - loadHTMLString:baseURL:
    设置网页内容和 base URL。
  • loading
    布尔值,显示当前视图是否正在加载。
  • - reload
    重新加载当前页面
  • - reloadFromOrigin
    重新加载当前页面,如果可能,使用缓存验证条件执行端到端重新验证。
  • - stopLoading
    停止加载当前页面所有资源。
  • - loadData:MIMEType:characterEncodingName:baseURL:
    设置网页内容和 base URL。
  • - loadFileURL:allowingReadAccessToURL:
    找到文件系统上所请求的文件URL

缩放内容

  • allowsMagnification
    布尔值,表示放大手势是否会改变网页视图的放大倍数。
  • magnification
    页面内容当前缩放因子。
  • - setMagnification:centeredAtPoint:
    按指定的因子缩放页面内容,并将结果居中在指定的点上。

导航

  • allowsBackForwardNavigationGestures
    布尔值,指示水平滑动手势是否会触发后退列表导航。默认为:NO。
  • backForwardList
    网页视图的后退列表。(之前访问过的 web 页面的列表)
  • canGoBack
    布尔值,指示后退列表中是否有可被导航到的后退项。
  • canGoForward
    布尔值,指示后退列表中是否有可导航的前进项。
  • allowsLinkPreview
    布尔值,用于确定是否按下链接可以显示链接目标的预览。
  • - goBack
    导航到后退列表中的后退项中。
  • - goForward
    导航到后退列表中的前进项中。
  • - goToBackForwardListItem:
    导航到后退列表中的某一个网页项,并将其设置为当前项。
  • - loadRequest:
    导航到请求的URL地址

执行 JavaScript

  • - evaluateJavaScript:completionHandler:
    评估 JavaScript 字符串。Objective-C 调用 JavaScript 方法

实例方法

  • - goBack
    导航到后退列表中的后退项中。
  • - goForward
    导航到后退列表中的前进项中。
  • - reload
    重新加载当前页面
  • - reloadFromOrigin
    重新加载当前页面,如果可能,使用缓存验证条件执行端到端重新验证。
  • - stopLoading
    停止加载当前页面所有资源。

WKWebViewConfiguration API

用于初始化Web视图的属性集合。

预览

使用 WKWebViewConfiguration 类,你可以确定网页呈现的速度,媒体播放的处理方式,用户可以选择的项目的粒度等等。

WKWebViewConfiguration 仅在首次初始化Web视图时使用。 当web视图被创建以后,你就无法再使用此类来更改Web视图的配置信息了。

Symbols

配置新的Web视图的属性

  • applicationNameForUserAgent
    在用户代理字符串中使用的应用程序的名称。
  • preferences
    Web视图要使用的首选项对象。
  • processPool
    从中获取视图的Web内容进程的进程池。
  • userContentController
    与网页视图关联的用户内容控制器。
  • websiteDataStore
    由网页视图使用的存储的网站数据。

确定页面可扩展性

  • ignoresViewportScaleLimits
    布尔值,用于确定 WKWebView 对象是否应始终允许缩放网页。

设置渲染首选项

  • suppressesIncrementalRendering
    布尔值,指示网络视图是否在【内容渲染完全加载到内存之前】禁止内容呈现。默认值:NO。

设置媒体播放首选项

  • allowsInlineMediaPlayback
    布尔值,指示HTML5视频是否内嵌播放或使用native全屏控制器。

  • allowsAirPlayForMediaPlayback
    是否允许 AirPlay

  • allowsPictureInPictureMediaPlayback
    HTML5视频是否可以播放画中画。

  • mediaTypesRequiringUserActionForPlayback
    确定哪些媒体类型需要用户手势才能开始播放。

  • WKAudiovisualMediaTypes
    枚举类型:需要用户手势开始播放的媒体类型

    typedef enum WKAudiovisualMediaTypes : NSUInteger {
        WKAudiovisualMediaTypeNone = 0,
        WKAudiovisualMediaTypeAudio = 1 << 0,
        WKAudiovisualMediaTypeVideo = 1 << 1,
        WKAudiovisualMediaTypeAll = NSUIntegerMax
    } WKAudiovisualMediaTypes;
    

设置选择粒度

  • selectionGranularity
    用户可以在网页视图中交互地选择内容的粒度级别。
  • WKSelectionGranularity
    枚举类型:交互式创建和修改选择的粒度。
    typedef enum WKSelectionGranularity : NSInteger {
        WKSelectionGranularityDynamic,    //选择粒度根据选择而自动变化。
        WKSelectionGranularityCharacter //选择端点可以放置在任何字符边界上
    } WKSelectionGranularity;
    

选择用户界面方向

  • userInterfaceDirectionPolicy
    用户界面元素的方向。

  • WKUserInterfaceDirectionPolicy
    枚举类型:用于确定Web视图中用户界面元素的方向性策略。

    typedef enum WKUserInterfaceDirectionPolicy : NSInteger {
        WKUserInterfaceDirectionPolicyContent,    // 方向遵循CSS / HTML / XHTML规范
        WKUserInterfaceDirectionPolicySystem // 方向遵循视图的userInterfaceLayoutDirection属性
    } WKUserInterfaceDirectionPolicy;
    


识别数据类型

  • dataDetectorTypes
    所需的数据检测类型。

  • WKDataDetectorTypes
    枚举类型:检测到的数据类型。

    typedef enum WKDataDetectorTypes : NSUInteger {
        WKDataDetectorTypeNone = 0,
        WKDataDetectorTypePhoneNumber = 1 << 0,
        WKDataDetectorTypeLink = 1 << 1,
        WKDataDetectorTypeAddress = 1 << 2,
        WKDataDetectorTypeCalendarEvent = 1 << 3,
        WKDataDetectorTypeTrackingNumber = 1 << 4,
        WKDataDetectorTypeFlightNumber = 1 << 5,
        WKDataDetectorTypeLookupSuggestion = 1 << 6,
        WKDataDetectorTypeAll = NSUIntegerMax,
        WKDataDetectorTypeSpotlightSuggestion = WKDataDetectorTypeLookupSuggestion
    } WKDataDetectorTypes;
    

WKNavigationDelegate API

WKNavigationDelegate 协议方法可以帮助你实现在Web视图接受,加载和完成导航请求的过程中触发的自定义行为。

初始化导航和跟踪加载进度

//  页面开始加载 web 内容时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

//  当 web 内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

//  页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

//  页面加载失败时调用 ( web 视图加载内容时发生错误)
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error;

// web 视图导航过程中发生错误时调用。
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;

// 当 Web 视图的 Web 内容进程终止时调用。
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;

导航错误:NSURLErrorDomain Code=-999
原因:webview 的上一个请求还没有加载完成,下一个请求发起了,此时 webview 会取消掉之前的请求,因此会回调导航失败错误(NSURLErrorCancelled = -999)。

响应服务器操作

// 收到服务器重定向之后调用 (接收到服务器跳转请求)
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;

实例方法

  • - webView:didReceiveAuthenticationChallenge:completionHandler:
    当 Web 视图需要响应认证挑战(authentication challenge)时调用。

当使用 HTTPS 协议加载 web 内容时,使用的证书不合法或者证书过期时需要使用该方法:

- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([challenge previousFailureCount] == 0) {
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        } else {
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        }
    } else {
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    }
}

允许导航

通常用于处理跨域的链接能否导航

// 在发送请求之前,决定是否允许或取消导航。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSLog(@"%s", __FUNCTION__);
    // 如果请求的是百度地址,则允许跳转
    if ([navigationAction.request.URL.host.lowercaseString isEqual:@"www.baidu.com"]) {
        // 允许跳转
        decisionHandler(WKNavigationActionPolicyAllow);
        return;
    }
    // 否则不允许跳转
    decisionHandler(WKNavigationActionPolicyCancel);
}

// 收到响应后,决定是否允许或取消导航。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    NSLog(@"%s", __FUNCTION__);
    // 如果响应的地址是百度,则允许跳转
    if ([navigationResponse.response.URL.host.lowercaseString isEqual:@"www.baidu.com"]) {
        // 允许跳转
        decisionHandler(WKNavigationResponsePolicyAllow);
        return;
    }
    // 否则不允许跳转
    decisionHandler(WKNavigationResponsePolicyCancel);
}

导航策略

  • WKNavigationActionPolicy
    decisionPolicyForNavigationAction:decisionHandler:方法返回的决定策略。

    typedef enum WKNavigationActionPolicy : NSInteger {
        WKNavigationActionPolicyCancel,
        WKNavigationActionPolicyAllow
    } WKNavigationActionPolicy;
    
  • WKNavigationResponsePolicy
    webView:decidePolicyForNavigationResponse:decisionHandler:方法返回的决定策略。

    typedef enum WKNavigationResponsePolicy : NSInteger {
        WKNavigationResponsePolicyCancel,
        WKNavigationResponsePolicyAllow
    } WKNavigationResponsePolicy;
    

WKUIDelegate API

WKUIDelegate 类是网页视图的用户界面委托协议,提供了代表网页呈现本机用户界面元素的方法。

Web视图用户界面委托对象实现此协议来控制打开的新窗口,增加用户单击元素时显示的默认菜单项的行为,并执行其他与用户界面相关的任务。 可以通过处理 JavaScript 或其他插件内容来调用这些方法。 默认Web视图实现假定每个Web视图有一个窗口,因此非常规用户界面可能会实现用户界面委托。

参考:【iOS 开发】WKWebView 学习笔记 (3)-WKUIDelegate

Symbols

创建 web 视图

  • - webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:
    创建一个新的 web 视图

显示 UI 面板

  • - webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:
    显示一个 JavaScript 警告面板。
  • - webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:
    显示一个 JavaScript 确认面板。
  • - webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:
    显示一个 JavaScript 文本输入面板。

关闭web视图

  • webViewDidClose:
    通知应用程序 DOM 窗口成功关闭。

显示上传面板

  • - webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:
    显示文件上传面板。

响应强制触控动作

  • - webView:shouldPreviewElement:
    确定给定元素是否应显示预览。
  • - webView:previewingViewControllerForElement:defaultActions:
    当用户执行窥视操作时调用。
  • - webView:commitPreviewingViewController:
    当用户在预览中执行弹出操作时调用。

OC 原生显示 JS 弹窗的正确方法

参考: WKWebView completionHandler called before dismissal @stackoverflow

// 显示一个 JavaScript 警告弹窗
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AlertPanel" message:message preferredStyle:UIAlertControllerStyleAlert];
    
    UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        // ⚠️必须在这里回调 JavaScript 
        completionHandler();
        
    }];
    [alertController addAction:alertAction];
    [self presentViewController:alertController animated:YES completion:nil];
    
}

WKUIDelegate 示例代码:

#pragma mark - WKUIDelegate

// 创建新的webView
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    WKFrameInfo *frameInfo = navigationAction.targetFrame;
    if (![frameInfo isMainFrame]) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

// 显示 JavaScript 警告框
// 测试JS代码:alert("alert message!")
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    [UIAlertController showAlertInViewController:self withTitle:@"温馨提示" message:message cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:@[@"确认"] tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) {
        completionHandler();
    }];
}

// 确认框
// 测试JS代码:confirm("confirm message!")
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    [UIAlertController showAlertInViewController:self withTitle:@"需要再次确认" message:message cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@[@"确认"] tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) {
        if (buttonIndex == 0) {
            completionHandler(NO);
        }else {
            completionHandler(YES);
        }
    }];
}

WKScriptMessageHandler API

遵守 WKScriptMessageHandler 协议的类,提供了从网页中运行 JavaScript 接收消息的方法。

// 从 web 界面中接收到一个脚本时调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

这个协议只包含以上一个必须实现的方法,这个方法是提高App与web端交互的关键,它可以直接将接收到的JS脚本转为 OC 或 Swift 对象。(当然,在 UIWebView 也可以通过“曲线救国”的方式与web进行交互,著名的Cordova 框架就是这种机制)

——WKWebView的新特性与使用 @saitjr

这个 API 真正神奇的地方在于 JavaScript 对象可以自动转换为 Objective-C 或 Swift 对象。

——WKWebView @nshipster

在 JavaScript 端通过 window.webkit.messageHandlers.{InjectedName}.postMessage() 方法来发送消息到native。我们需要遵守该协议,然后实现代理方法,就可以收到消息,并做相应的的处理。

如果在开始时就注入很多的名称,就需要区分处理

if (message.name == "AppModel" ) {
//...
}

——WKWebView特性及使用 @360doc 【Swift】

WKUserScript API

WKUserScript 对象表示可以注入到网页中的脚本。

Symbols

初始化脚本

  • -initWithSource:injectionTime:forMainFrameOnly:
    返回可以添加到用户内容控制器中的初始化用户脚本。

检查脚本信息

  • source
    脚本源代码
  • injectionTime
    脚本应该被注入网页中的时间点。
  • forMainFrameOnly
    布尔值,指示脚本是否仅应注入主框架(是)或所有框架(否)。

常量

  • WKUserScriptInjectionTime
    将用户脚本注入网页的时间。
typedef enum WKUserScriptInjectionTime : NSInteger {
    WKUserScriptInjectionTimeAtDocumentStart, // 在文档元素创建之后,但在加载任何其他内容之前注入脚本。
    WKUserScriptInjectionTimeAtDocumentEnd //在文件完成加载后,但在其他子资源完成加载之前注入该脚本。
} WKUserScriptInjectionTime;

WKUserScript 对象可以以 JavaScript 源码形式初始化,初始化时还可以传入时间是在加载之前还是结束时注入,以及脚本影响的是这个布局还是仅主要布局。于是用户脚本被加入到 WKUserContentController 中,并且以 WKWebViewConfiguration 属性传入到 WKWebView 的初始化过程中。

- (void)viewDidLoad {
    [super viewDidLoad];
  
    // 使用 WKUserScript 注入JavaScript脚本
    // 图片缩放的js代码
    NSString *js = @"var count = document.images.length;for (var i = 0; i < count; i++) {var image = document.images[i];image.style.width=320;};window.alert('找到' + count + '张图');";
    
    // 根据JS字符串初始化 WKUserScript 对象
    WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    
    // 根据生成的 WKUserScript 对象,初始化 WKWebViewConfiguration 对象
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    [config.userContentController addUserScript:script];
    
    // 初始化 WKWebView 对象
    _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    _webView.UIDelegate = self;
    _webView.navigationDelegate = self;
    [_webView loadHTMLString:@"![](http://upload-images.jianshu.io/upload_images/2648731-54ae5490e32407cf.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)" baseURL:nil];
    [self.view addSubview:_webView];
    
}

使用示例:自适应文本字体大小

场景:加载的 HTML 网页没有对移动端设备屏幕做适配,导致加载后显示的字体太大或者太小,影响用户体验,通过注入 JavaScript 脚本的方式可以解决这个问题。
以下为代码示例:

- (WKWebViewConfiguration *)webViewConfiguration {
    if (!_webViewConfiguration) {
        _webViewConfiguration = [[WKWebViewConfiguration alloc] init];
        
        // 自适应字体
        NSString *javaScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        WKUserContentController *contentController = [[WKUserContentController alloc] init];
        [contentController addUserScript:userScript];
        _webViewConfiguration.userContentController = contentController;
    }
    return _webViewConfiguration;
}

你可能感兴趣的:(WKWebView API)