IOS基础知识-UIWebView与WKWebView的区别

通过简单的测试即可发现UIWebView占用过多内存,且内存峰值更是夸张。WKWebView网页加载速度也有提升,但是并不像内存那样提升那么多。下面列举一些其它的优势:

更多的支持HTML5的特性
官方宣称的高达60fps的滚动刷新率以及内置手势
Safari相同的JavaScript引擎
将UIWebViewDelegate与UIWebView拆分成了14类与3个协议(官方文档说明)
另外用的比较多的,增加加载进度属性:estimatedProgress

UIWebView
OC调用JS

  • (nullable NSString *)stringByEvaluatingJavaScriptFromString:

JS调用OC
让Native 代码拦截, - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest:)request navigationType:(UIWebViewNavigationType)navigationType

方案中进行拦截处理。
WKWebView
OC调用JS

  • (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^_Nullable)(_Nullable id,NSError * _Nullable error))completionHandler;

WKWebView 本身提供一个方法进行处理JS代码

  • (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

JS调用OC
在JS端的操作
window.webkit.messageHandlers.<方法名>.postMessage(<数据>)

在OC中的处理方法

  • (void)addScriptMessageHandler:(id)scriptMessageHandler name:(NSString *)name;

具体如下
//设置addScriptMessageHandler与name.并且设置协议与协议方法
[[_webView configuration].userContentController addScriptMessageHandler:self name:@"方法名"];

//WKScriptMessageHandler协议方法

  • (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    //code
    }

如果你在self的dealloc打个断点,会发现self没有释放,这显示是不行的。
思路是另外创建一个代理对象,然后通过代理对象回调指定的self。

WKWebView 坑
WKWebView 白屏问题
WKWevView Cookie 问题
WKWebView NSURLProtocol问题

WKWebView 在独立于app进程之外的进程中执行网络请求,请求数据不经过主进程,因此,在WKWebView上直接使用NSURLProtocol无法拦截请求。
post 请求body 数据被清空(encode的时候HTTPBody和HTTPBodyStream 这两个字段被丢弃了)

由于 WKWebView 在独立进程里执行网络请求。一旦注册 http(s) scheme 后,网络请求将从 Network Process 发送到 App Process,这样 NSURLProtocol 才能拦截网络请求。在 webkit2 的设计里使用 MessageQueue 进行进程之间的通信,Network Process 会将请求 encode 成一个 Message,然后通过 IPC 发送给 App Process。出于性能的原因,encode 的时候 HTTPBody 和 HTTPBodyStream 这两个字段被丢弃掉了(参考苹果源码:
https://github.com/WebKit/webkit/blob/fe39539b83d28751e86077b173abd5b7872ce3f9/Source/WebKit2/Shared/mac/WebCoreArgumentCodersMac.mm#L61-L88 及bug report: )。

对ATS支持不足

测试发现一旦打开ATS开关:Allow Arbitrary Loads 选项设置为NO,同时通过 registerSchemeForCustomProtocol 注册了 http(s) scheme,WKWebView 发起的所有 http 网络请求将被阻塞(即便将Allow Arbitrary Loads in Web Content 选项设置为YES);
WKWebView 可以注册 customScheme, 比如 dynamic://, 因此希望使用离线功能又不使用 post 方式的请求可以通过 customScheme 发起请求,比如 dynamic://http://www.dynamicalbumlocalimage.com/,然后在 app 进程 NSURLProtocol 拦截这个请求并加载离线数据。不足:使用 post 方式的请求该方案依然不适用,同时需要 H5 侧修改请求 scheme 以及 CSP 规则

WKWebView loadRequest 问题

在WKWebView 上通过loadRequ发起的post请求body数据被丢失

//同样是由于进程间通信性能问题,HTTPBody字段被丢弃
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[@"bodyData" dataUsingEncoding:NSUTF8StringEncoding]];
[wkwebview loadRequest: request]

WKWebView 页面样式问题
WKWebView 截屏问题
WkWebView crash 问题

WKWebView的三个代理
WKNavigationDelegate:最常用,和UIWebViewDelegate功能类似,追踪加载过程,有是否允许加载、开始加载、加载完成、加载失败。下面会对函数做简单的说明,并用数字标出调用的先后次序1-2-3-4-5

/// 接收到服务器跳转请求之后调用 (服务器端redirect),不一定调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation; 
/// 3 在收到服务器的响应头,根据response相关信息,决定是否跳转。decisionHandler必须调用,来决定是否跳转,参数WKNavigationActionPolicyCancel取消跳转,WKNavigationActionPolicyAllow允许跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
/// 1 在发送请求之前,决定是否跳转 
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
/// 2 页面开始加载
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
/// 4 开始获取到网页内容时返回
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
/// 5 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
/// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

WKScriptMessageHandler:必须实现的函数,是APP与js交互,提供从网页中收消息的回调方法,即js可以调用app的方法;

/// message: 收到的脚本信息.
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

当然,app也可以执行js代码,如下:
/// jsStr为要执行的js代码,字符串形式
[webView evaluateJavaScript:jsStr completionHandler:^(id item, NSError * _Nullable error) {
        // 执行结果回调
}];

WKUIDelegate:UI界面相关,原生控件支持,三种提示框:输入、确认、警告。首先将web提示框拦截然后再做处理

/// 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
/// 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
/// 确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
/// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

你可能感兴趣的:(IOS基础知识-UIWebView与WKWebView的区别)