概述:在iOS8中加入,用来替代UIWebView的控件。比UIWebView加载快一倍的控件,内存方面却比UIWebView少一半,但是相对的缓存处理方面会稍微差一点;
优缺点:
优点:
1)、将浏览器内核渲染进程提取出 App,由系统进行统一管理,这减少了相当一部分的性能损失。
2)、js 可以直接使用已经事先注入 js runtime 的 js 接口给 Native 层传值,不必再通过苦逼的 iframe 制造页面刷新再解析自定义协议的奇怪方式。
3)、支持高达 60 fps 的滚动刷新率,内置了手势探测。
4)、支持了更多的HTML5特性。
缺点:
1)、WK对缓存和Cookie操作没有UIWebView那么方便。(调用的API没有那么显著的用途。)
2)、WK从iOS8才开始支持,也就是说在我们同时对iOS7支持的情况下,如果为了减少代码量及适配等方面因素,一样会选择UIWebView。
3)、WkWebView不可以实现NSURLProtocol 拦截
分析一下UIWebView缓存机制
1、NSURLRequestUseProtocolCachePolicy NSURLRequest默认的cache policy,使用Protocol协议定义。
2、NSURLRequestReloadIgnoringCacheData 忽略缓存直接从原始地址下载。
3、NSURLRequestReturnCacheDataElseLoad 只有在cache中不存在data时才从原始地址下载。
4、NSURLRequestReturnCacheDataDontLoad 只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式;
5、NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地和远程的缓存数据,直接从原始地址下载,与NSURLRequestReloadIgnoringCacheData类似。
6、NSURLRequestReloadRevalidatingCacheData:验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据。
Notes:
The WebKit framework is not thread-safe. If you call functions or methods in this framework, you must do so exclusively on the main program thread.
UIWebView回顾:
WKWebView:
WKWebview属性:
新增属性:
// UIWebView 中会自动保存Cookie,如果登录了一次下次再次进入的时候,会记住登录状态
// 在WKWebView中,新增一个configuration属性, configuration 让WKWebView知道登录状态,configuration 可以通过已有的Cookie进行设置,也可以通过保存上一次的configuration进行设置
// WKWebViewConfiguration类中也有一些相应的属性
@property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
//WKWebView中,加入了网站导航的概念,这个对象决定主框架导航加载方法协议
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
// WKWebView中,加入了网站窗口的概念,这个对象决了webView窗口的一些方法协议。
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;
// WKWebView中,加入了网站列表的概念,这个WEBBackForwardList对象是以前在Web视图访问的网页,可以通过去后退或前进
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
//WKWebView新加入了一次请求的进度的属性,新的Request会重置上次请求的进度
//[_wkWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:WkwebBrowserContext];
@property (nonatomic, readonly) double estimatedProgress;
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
@property (nonatomic, readonly, nullable) SecTrustRef serverTrust API_AVAILABLE(macosx(10.12), ios(10.0));
// 新增了左滑右滑的手势
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
@property (nullable, nonatomic, copy) NSString *customUserAgent API_AVAILABLE(macosx(10.11), ios(9.0));
@property (nonatomic) BOOL allowsLinkPreview API_AVAILABLE(macosx(10.11), ios(9.0));
WKWebView的方法:
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0));
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));
- (nullable WKNavigation *)goBack;
- (nullable WKNavigation *)goForward;
- (nullable WKNavigation *)reload;
新增方法:
// 前进或者后退到某页
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
//重新加载原始URL,会比较网络数据是否有变化,没有变化则使用缓存,否则从新请求
- (nullable WKNavigation *)reloadFromOrigin;
/*! @abstract Stops loading all resources on the current page.
*/
- (void)stopLoading;
// Native通过该方法调用JavaScript,completionHandler执行的回调结果
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
//根据设置的缩放率来缩放页面,并居中显示结果在指定的点
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(CGPoint)point;
WKWebView相关协议:
1)、WKScriptMessageHandler
提供接收网页JS调用的方法
//拦截执行网页中的JS方法
//服务器固定格式写法 window.webkit.messageHandlers.名字.postMessage(内容);
//客户端写法 message.name isEqualToString:@"名字"]
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
2)、WKNavigationDelegate
可以用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转,还能监听服务器跳转、身份认证等
a、页面开始加载、加载完成、加载失败
//页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
//当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
//页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
b、页面跳转的代理方法有三种,分为(收到跳转与决定是否跳转两种)
//接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
// 发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
//在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
c、导航错误、身份认证、webview进程终止
//WKNavigation导航错误
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
// 身份验证
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
//WKWebView进程终止,9.0以后才能使用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
3)、WKUIDelegate
作用:通过该协议,展示本地UI,如AlertView等
// 创建一个新的wkWebview
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
- (void)webViewDidClose:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
界面弹出提示框相关
// 获取js 里面的提示
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
// js 信息的交流
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
// 交互。可输入的文本。
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;
iOS10 新增3D touch API
用户在WKWebView中使用3D Touch查看和弹出链接就可以显示自定义视图控制器
//当用户触摸元素时webView(_:shouldPreviewElement:)立即被调用。返回NO将完全禁用该元素的预览,并且阻止其他方法的调用。返回YES将提供一个自定义视图控制的机会,前提是用户触摸时有足够的力度来启动查看
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo API_AVAILABLE(ios(10.0));
//如果用户输入Peek,那么webView(_:previewingViewControllerForElement:defaultActions:)为其提供了一个定制视图控制器的机会。返回任何非空视图控制器都会导致视图控制器显示为Peek预览。defaultActions参数是一个活动数组,WebKit Webkit默认使用它作为previewActionItems。如果想要使用这些活动中的任何一个,你只需从视图控制器的previewActionItems执行结果中返回即可
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions API_AVAILABLE(ios(10.0));
// 用户用足够的力触摸来弹出视图控制器,webView(_:commitPreviewingViewController:)将被调用。此时,你可以选择在app中展示弹出的视图控制器
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController API_AVAILABLE(ios(10.0));
WKWebView更好的与Web交互
回顾UIWebView的方式:
- delegate方法
webViewDidFinishLoad
中注入JS源码
NSString *js = @"js代码";
[webView stringByEvaluatingJavaScriptFromString:js];
- 调用native方法
当html调用这段注入的JS方法后,会将hybrid://invoke? 以及后面拼接的内容以IFrame的方式进行加载,在加载的同时会出发APP的delegate方法
在shouldStartLoadWithRequest方法中解析:
NSString *url = request.URL.absoluteString;
if(url != nil && [url hasPrefix:@"hybrid://invoke?"]){
return NO;
}
WKWebView -- Web 调 APP
1.在webview初始化之前先注册一个名为hybridDemo的handler对象。
WKWebViewConfiguration *config =[[WKWebViewConfiguration alloc]init];
[config.userContentController addScriptMessageHandler:self name:@"webViewApp"];
webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
2.在html端调用JS来访问之前注册的handler对象,并通过调用postMessage方法把数据传到app。
var message = {"method":"hello","args":"let go"};
window.webkit.messageHandlers.webViewApp.postMessage(message);
3.在webview容器中实现上文提过的WKScriptMessageHandler委托,从而响应来自于JS端下发的message
//拦截执行网页中的JS方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
//服务器固定格式写法 window.webkit.messageHandlers.名字.postMessage(内容);
//客户端写法 message.name isEqualToString:@"名字"]
[XYWebViewEventService executeWithEventId:message.name paramater:message.body];
}
// 图片缩放的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 loadHTMLString:@"<head></head>![](http://upload-images.jianshu.io/upload_images/2344965-67a790ebf8cdb9e4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)"baseURL:nil];
[self.view addSubview:webView];