前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WKWebView

WKWebView

作者头像
拉维
发布2019-08-12 15:53:35
5.9K0
发布2019-08-12 15:53:35
举报
文章被收录于专栏:iOS小生活iOS小生活

在iOS中,加载网页目前有两种控件:UIWebView和WKWebView。

UIWebView自iOS2就有,WKWebView从iOS8.0(2014年9月WWDC)才有,毫无疑问,WKWebView相对UIWebVIew要优秀得多,主要表现在以下几点:

1,WKWebView拥有60fps的滚动刷新率,页面更流畅

2,WKWebView拥有与Safari中相同的Nitro JavaScript引擎,大大提高了页面JS执行速度;但是UIWebView不支持Nitro JavaScript引擎,所以加载较慢。

3,WKWebView的内存占用大概是UIWebView的1/3~1/4,内存占用更低(可以查看该文:https://www.jianshu.com/p/181889939a85)。

4,WKWebView增加了estimatedProgress属性用以实现进度条。

5,WKWebView可以和JS直接互调函数,交互更方便;而UIWebView则需要依靠WebViewJavaScriptBridge第三方库来协助处理与JS的交互,实现起来较繁琐。

6,WKWebView是多进程组件,这意味着会从APP内存中分离内存到单独的进程中。但WKWebView的内存超过系统分配给它的内存的时候,WKWebView浏览器就会崩溃白屏,但是APP不会crash(APP会收到系统通知,并且尝试去重新加载页面)。

相反,UIWebView是和APP是同一个进程,UIWebView加载页面占用的内存被计算为APP内存占用的一部分,当APP超过了系统分配的内存,则会被操作系统crash。

7,UIWebView对html5的各种规范支持较少,而WKWebView由于是基于WebKit所以对h5的各种规则基本都支持。

以上介绍了WKWebView的优点,但是其也有以下缺点:

1,WKWebView需要iOS9及更高的版本,虽然WKWebView是在iOS8之后引入的,但是iOS8的版本存在重大限制,比如无法访问本地存储的文件,而支持比较全面是在iOS9以后的版本。

2,截屏捕获在WKWebView上会随机失败,因此,如果截屏的API是App中的关键操作,那么建议使用现有的UIWebView浏览引擎。

其他的区别如下:

1,UIWebView是UIKit框架的一部分,可以在应用程序内使用,无需导入任何内容;而WKWebView使用的是WebKit.framework,使用的时候需要导入到应用程序中。

WKWebView的用法

WKWebView API

WKWebView对象可以显示交互式Web内容,例如应用内浏览器。你可以使用WKWebView类将web内容嵌入到你的应用程序中。

使用概览

使用 - initWithFrame:configuration: 创建一个新的WKWebView对象。

然后就可以通过 - loadHTMLString:baseURL: 方法或者 - loadRequest: 方法加载网页内容。

可以使用stopLoading方法来停止页面的加载,使用loading属性来查看是否正在加载。

要允许用户在Web历史页面中前进或者后退,要为按钮设置goBack或者goForward的动作。当用户不能在某个方向上再移动时,使用canGoBack或者canGoForward来禁用按钮。

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

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

初始化Web视图

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

查看web信息

  • scrollView。与WebView相关联的滚动视图。
  • title。页面标题
  • URL。活动网址
  • customUserAgent。自定义用户代理字符串

设置委托

  • navigationDelegate
  • UIDelegate

加载内容

  • estimatedProgress。值为0-1,表示当前页面加载的进度。
  • hasOnlySecureContent。布尔值,表示页面上的所有资源是否通过安全加密的连接加载。
  • - loadHTMLString:baseURL:。设置网页内容和baseUrl
  • loading。布尔值,显示当前页面是否正在加载。
  • - reload。重新加载当前页面。
  • - reloadFromOrigin。重新加载当前页面,如果可能,使用缓存验证条件执行端到端重新验证。
  • - stopLoading。停止加载当前页面所有资源。
  • -loadData: MIMEType: characterEncodingName: baseURL:
  • -loadFileURL: allowingReadAccessToURL:

缩放内容

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

导航

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

执行JavaScript

  • - evaluateJavaScript:completionHandler:。苹果JS字符串,用于OC调用JS方法。

实例方法

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

WKWebViewConfiguration API

使用WKWebViewConfiguration类,你可以确定网页呈现的速度、媒体播放的处理方式等等。

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

配置新的web视图的属性

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

确定页面可扩展性

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

设置渲染首选项

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

设置媒体播放首选项

  • allowsInlineMediaPlayback。布尔值,指示HTML5视频是否内嵌播放,或使用native全屏控制器。
  • allowsAirPlayForMediaPlayback。是否允许AirPlay。
  • allowsPictureInPictureMediaPlayback。HTML5视图是否可以播放画中画
  • mediaTypesRequiringUserActionForPlayback。确定哪些类型需要用户手势才能播放。
  • WKAudiovisualMediaTypes。枚举类型,需要用户手势开始播放的媒体类型。

设置选择粒度

  • selectionGranularity。用户可以在网页视图中交互地选择内容的粒度级别。
  • WKSelectionGranularity。枚举类型,交互式创建和修改选择的粒度。

选择用户界面方向

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

识别数据类型

  • dataDetectorTypes。所需的数据监测类型。
  • WKDataDetectorTypes。枚举类型,监测到的数据类型。

WKNavigationDelegate API

WKNavigationDelegate系列的相关协议方法,监管了WebView加载前前后后的整个流程。

// 在传给WKWebView一个webUrl的时候,WebView决定是否加载该请求。比如JS与Native的通信、scheme拦截、点击电话号码是否调起拨打电话的弹窗等,都是在该代理方法中处理的。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
}
// 收到响应后,决定是否允许或取消导航。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
}
//页面开始加载web内容
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
}
//收到服务器重定向之后调用 (接收到服务器跳转请求)
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
}
//页面加载失败时调用 (【web视图加载内容时】发生错误)
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
{
}
//web内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation
{
}

//页面加载完成之后调用

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
}

//页面加载失败时调用

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
{
}

//当 Web 视图需要响应认证挑战(authentication challenge)时调用。当使用 Https 协议加载web内容时,使用的证书不合法或者证书过期时需要使用该方法.

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
}

// 当Web视图的Web内容进程终止时调用,可在该函数中重新创建新的WKWebView,然后自动重新加载页面。一般而言,但WKWebView因一些稀奇古怪的原因导致Crash的时候就会回调该方法。

代码语言:javascript
复制
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
{
}

WKUIDelegate API

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

WKUIDelegate的代理方法我们用到的不多,其主要是处理一些页面中常用到的JS逻辑,比如alert、confirm等。

//创建一个新的 web 视图

代码语言:javascript
复制
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
}

//通知您的应用程序DOM窗口成功关闭。

代码语言:javascript
复制
- (void)webViewDidClose:(WKWebView *)webView
{
}

//显示一个 JavaScript 警告面板。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
 //这里展示了如何使用OC原生来展示JS的警告弹窗
 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AlertPanel"message:message preferredStyle:UIAlertControllerStyleAlert];
 UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {
 // ⚠️必须在这里回调 JavaScript
        completionHandler();
    }];
    [alertController addAction:alertAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

//显示一个 JavaScript 确认面板。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
{
}

//显示一个 JavaScript 文本输入面板。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler
{
}

//确定给定元素是否应显示预览。

代码语言:javascript
复制
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo
{
}

//当用户执行窥视操作时调用。

代码语言:javascript
复制
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions
{
}

//当用户在预览中执行弹出操作时调用。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController
{
}

//显示文件上传面板。

代码语言:javascript
复制
- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler
{
}

以上就是WKWebView的一些基础的API,下面来聊聊WKWebView的基本使用。

显示加载进度条

我们可以通过监听WKWebView的estimatedProgress属性值来实现一个加载进度条,而UIWebView只能是通过timer事件做一个假的加载进度条。

给WKWebView做一个进度条的步骤如下:

1,声明并初始化一个UIProgressView

代码语言:javascript
复制
@property(nonatomic , strong) UIProgressView  *progressView;//声明进度条
//初始化进度条视图
- (UIProgressView *)progressView
{
 if (_progressView == nil) {
 CGRect frame = CGRectMake(0, XYWKNavHeight, XYWKScreenW, 5);
 _progressView = [[UIProgressView alloc] initWithFrame:frame];
 _progressView.tintColor = UIColor.blueColor;// 设置进度条色调
 _progressView.trackTintColor = kWhiteColor;//设置进度条跟踪色调
    }
 return _progressView;
}

2,监听WKWebView的estimatedProgress属性

代码语言:javascript
复制
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNewcontext:NULL];

3,实现- observeValueForKeyPath: ofObject:(id)object change: context:方法,并改变progressView的progress属性

代码语言:javascript
复制
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
 if ([keyPath isEqualToString:@"estimatedProgress"]) {
 if (object == self.webView) {
 if (self.shouldShowProgress) {
                [self showLoadingProgress:self.webView.estimatedProgress];
            }
        }
 else{
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
 else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
- (void)showLoadingProgress:(CGFloat)progress{
 if (!self.progressView.superview) {
 //将进度条添加到视图上
        [self.view addSubview:self.progressView];
    }
 self.progressView.progress = progress;
 // 如果progress = 1.0 自动移除
 if(progress == 1.0f)
    {
        [self hideLoadingProgressView];
    }
}

4,移除观察者

代码语言:javascript
复制
- (void)dealloc {
 XYWKLog(@"dealloc --- %@",NSStringFromClass([selfclass]));
 if (self.shouldShowProgress) {
        [self.webView removeObserver:selfforKeyPath:@"estimatedProgress"];
    }
}

给WKWebView添加加载进度条,说白了无非就是使用KVO监听WebView的estimatedProgress属性,然后改变progressView 的progress属性值。关于KVO,我在之前的文章iOS开发中的设计模式--观察者模式中详述过。

其他

1,HTML构建各个组件,CSS给各个组件添加样式(字体大小、颜色等),JavaScript添加交互(点击响应、动画等)。

2,不管是WKWebView还是UIWebView,其实其本质都是一个能够通过网址直接获取到数据流,并将数据流解析渲染出来的组件

3,WebKit是一个开源的浏览器引擎,当前常见的浏览器基本都是基于WebKit进行延伸的。而iOS中的WebKit.framework,就是在WebCore、底层桥接、JSCore引擎等核心模块的基础上,针对iOS平台的项目封装。WKWebView就是基于WebKit.framework。

4,WKWebView的configuration属性主要是进行web前端相关业务逻辑的配置。

5,使用WKWebView的流程如下:

  1. 创建并初始化一个WKWebView
  2. 设置WebView的navigationDelegate、UIDelegate、configuration等
  3. 加载URL或者HTML字符串
  4. 在相应的代理方法回调中处理业务逻辑,

6,上面讲到,我们可以使用KVO来监听WKWebView的estimatedProgress属性值的变化来实现加载进度条,那么WKWebView中还有那些属性值的变化也是可以被KVO监听到的呢?凡是在WKWebView的属性描述中带有“is key-value observing (KVO) compliant for this property”字样的属性,都是可以通过KVO来观察到其值变化的,比如estimatedProgress、title、canGoBack、canGoForward等属性。

7,本文主要介绍了如何通过WKWebView来展示一个页面,其实,WKWebView不仅仅只有展示的功能,它还能够和Native进行交互。而且iOS中的web应用,起重点就是与Native进行交互

在iOS中,JavaScript和Native进行交互,主要是依靠JSBridge或者JavaScriptCore。JavaScriptCore是在iOS7之后推出的,之前都是使用JSBridge。我们可以通过JSCore或者JSBridge来在native中执行JS代码,并且在JS中去回调Native的相关函数

现在很火热的跨平台以及热修复技术,都是基于JS与Native通信来实现的。不管你是使用Weex、RN还是Flutter,其程序运行的终端都是iOS或者Android,我们选择JavaScript这门较为通用的语言来调动iOS或者Android,而iOS中又内嵌了JavaScriptCore这个基础组件可以实现JS与Native之间的通信。很多跨平台技术,其核心就是利用了JS与Native的通信技术。

以上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档