WKWebView

文章目录

  • WKWebView
    • 简介
    • WKWebViewConfiguration
      • websiteDataStore
      • WKUserContentController
    • 创建
    • 动态注入 js
    • 加载
    • 代理
    • 新增属性
    • Reference

简介

WKWebView 是Apple iOS8 之后推出的webkit的核心控件,用来替换UIWebView。相比UIWebView,WKWebView优势在于:

  1. 更多的支持html5特性
  2. 高达60fps的滚动刷新率及内置手势
  3. 与safari相同的 Nitro javascript引擎
  4. 将UIWebViewDelegate与UIWebView拆分成了14类与3个协议
  5. 可以获取加载进度,不需要调用私有API
  • WKWebView 是苹果在 WWDC 2014 上推出的新一代 webView 组件,用以替代 UIKit 中笨重难用、内存泄漏的 UIWebView;WKWebView 拥有60fps滚动刷新率、和 safari 相同的 JavaScript 引擎等优势。

  • 速度快了一倍,内存却减少为原来的一半

  • 交互更加顺畅,比如app底部四个tabBar也都是网页的,在UIWebView下点击,整个H5页都会闪白一下,但是在WKWebView下点击,四个tabBar效果与原生app效果更加类似,不会有闪白现象;

  • WKWebView 自诩拥有更快的加载速度,更低的内存占用,但实际上 WKWebView 是一个多进程组件,Network Loading 以及 UI Rendering 在其它进程中执行。初次适配 WKWebView 的时候,我们也惊讶于打开 WKWebView 后,App 进程内存消耗反而大幅下降,但是仔细观察会发现,Other Process 的内存占用会增加。在一些用 webGL 渲染的复杂页面,使用 WKWebView 总体的内存占用(App Process Memory + Other Process Memory)不见得比 UIWebView 少很多。

  • 在 UIWebView 上当内存占用太大的时候,App Process 会 crash;而在 WKWebView 上当总体的内存占用比较大的时候,WebContent Process 会 crash,从而出现白屏现象。在 WKWebView 中加载下面的测试链接可以稳定重现白屏现象: http://people.mozilla.org/~rnewman/fennec/mem.html
    这个时候 WKWebView.URL 会变为 nil, 简单的 reload 刷新操作已经失效,对于一些长驻的H5页面影响比较大。

  • 增减了一些代理方法,更方便的进行协议拦截和进度条展示

  • cookie不再是自动携带,需要手动设置

WKWebViewConfiguration

WKWebView比UIWebView多了一个configuration,可以配置很多东西,比如js是否支持、画中画、是否内联视频播放、偏好设置等,具体可以在WKWebViewConfiguration里查看。

websiteDataStore

重点要说的是 websiteDataStore

/*! @abstract The website data store to be used by the web view.*/
@property (nonatomic, strong) WKWebsiteDataStore *websiteDataStore API_AVAILABLE(macosx(10.11), ios(9.0));

一般认为WKWebView拥有自己的私有存储,一些缓存数据都存在 websiteDataStore 里,可以通过 WKWebsiteDataStore.h 里提供的方法进行增删改插。但实际真正要清除缓存,还是直接删除沙盒里的cache文件

WKWebsiteDataStore在iOS 9中引入,是一个新的API,它用于管理一个网站站点存储的数据,例如Cookies,它是你网页的 WKWebViewConfiguration上的一个可读写的属性。你可以根据类型或者时间来删除数据,例如Cookies和缓存,你可以用非持久性数 据存储来改变配置。

WKUserContentController

/*! @abstract The user content controller to associate with the web view.
*/
@property (nonatomic, strong) WKUserContentController *userContentController;

这个属性很重要,js和oc交互,js代码注入都会用到。WKUserContentController头文件里可以发现一下几个方法

@interface WKUserContentController : NSObject <NSCoding>
//读取添加过的脚本
@property (nonatomic, readonly, copy) NSArray<WKUserScript *> *userScripts;
//添加脚本
- (void)addUserScript:(WKUserScript *)userScript;
//删除所有添加的脚本
- (void)removeAllUserScripts;//通过window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 来实现js->oc传递消息,并添加handler
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
//删除handler
- (void)removeScriptMessageHandlerForName:(NSString *)name;
@end

创建

WKWebView 的创建方法有这两种

//1、
-initWithFrame: to initialize an instance with the default configuration.
//如果使用initWithFrame方法将使用默认的configuration
//The initializer copies the specified configuration, so mutating the configuration after invoking the initializer has no effect on the web view.
//需要先设置configuration,再调用init,在init之后修改configuration则无效
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;//2、
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

创建 WKWebView

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *controller = [[WKUserContentController alloc] init];
configuration.userContentController = controller;self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
self.webView.allowsBackForwardNavigationGestures = YES; //允许右滑返回上个链接,左滑前进
self.webView.allowsLinkPreview = YES; //允许链接3D Touch
self.webView.customUserAgent = @"WebViewDemo/1.0.0"; //自定义UA,UIWebView就没有此功能,后面会讲到通过其他方式实现
self.webView.UIDelegate = self;
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];

动态注入 js

给userContentController添加WKUserScript,可以实现动态注入js。比如注入一个脚本给页面添加cookie

//注入一个Cookie
WKUserScript *newCookieScript = [[WKUserScript alloc] initWithSource:@"document.cookie = 'DarkAngelCookie=DarkAngel;'" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[self.configuration.userContentController addUserScript:newCookieScript];

然后再注入一个脚本,每当页面加载,就会alert当前页面cookie,在OC中的实现

//创建脚本
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:@"alert(document.cookie);" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
//添加脚本
[self.configuration.userContentController addUserScript:script];

注入的js source可以是任何js字符串,也可以是js文件。比如有很多提供给h5使用的js方法,本地就可以有一个native_functions.js,可以使用下面方式添加

//防止频繁IO操作,造成性能影响
static NSString *jsSource;
static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{jsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"native_functions" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
});
//添加自定义的脚本
WKUserScript *js = [[WKUserScript alloc] initWithSource:jsSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
[self.configuration.userContentController addUserScript:js];

加载

加载页面的API

- (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));

加载本地的一个html需要使用loadRequest:方法,使用loadHTMLString:baseURL:方法会有问题

[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"]]]];

代理

在WKWebView的头文件,可以看到两个代理

@protocol WKNavigationDelegate; //类似于UIWebView的加载成功、失败、是否允许跳转等
@protocol WKUIDelegate;         //主要是一些alert、打开新窗口之类的

UIWebView的代理拆成了一个跳转协议和一个关于UI的协议。虽说这两个协议都是Optional,但还是有些问题的。先说一下常见用法

//下面这2个方法共同对应了UIWebView的 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
//先:针对一次action来决定是否允许跳转,action中可以获取request,允许与否都需要调用decisionHandler,比如decisionHandler(WKNavigationActionPolicyCancel);
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;//后:根据response来决定,是否允许跳转,允许与否都需要调用decisionHandler,如decisionHandler(WKNavigationResponsePolicyAllow);
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;//开始加载,对应UIWebView的- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;//加载成功,对应UIWebView的- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;//加载失败,对应UIWebView的- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;

新增属性

WKWebView.h定义了如下几个常用的readonly属性:

@property (nullable, nonatomic, readonly, copy) NSString *title;    //页面的title,终于可以直接获取了
@property (nullable, nonatomic, readonly, copy) NSURL *URL;         //当前webView的URL
@property (nonatomic, readonly, getter=isLoading) BOOL loading;     //是否正在加载
@property (nonatomic, readonly) double estimatedProgress;           //加载的进度
@property (nonatomic, readonly) BOOL canGoBack;                     //是否可以后退,跟UIWebView相同
@property (nonatomic, readonly) BOOL canGoForward;                  //是否可以前进,跟UIWebView相同

这些属性都支持kvo,可以使用kvo观察这些值的变化。

Reference

WKWebView:JavaScript与OC交互、Cookie管理、常见问题

UIWebView/WkWebView用法的一些总结

iOS开发实战-Cookie注入

WKWebView 基础篇

WKWebView 协议篇

WKWebView 实战篇

WKWebView-基础篇相关推荐

  1. Python Qt GUI设计:信号与槽的使用方法(基础篇—7)

    目录 1.信号与槽的概念 2.信号与槽的基础函数 2.1.创建信号函数 2.2.连接信号函数 2.3.断开信号函数 2.4.发射信号函数 3.信号和槽的使用方法 3.1.内置信号与槽的使用 3.2.自 ...

  2. Python Qt GUI设计:窗口布局管理方法【强化】(基础篇—6)

    目录 1. 水平布局类(QHBoxLayout) 2.垂直布局类(QVBoxLayout) 3.网格布局类(QGridLayout) 3.1.单一的网络布局 3.2.跨越行.列的网络布局 4.表单布局 ...

  3. Python Qt GUI设计:窗口布局管理方法【基础】(基础篇—5)

    目录 1.布局管理器进行布局 2.容器控件进行布局 3.geometry属性:控件绝对布局 4.sizePolicy属性:微调优化控件布局 Qt Designer提供4种窗口布局方式,分别如下: Ve ...

  4. ES6 你可能不知道的事 – 基础篇

    ES6 你可能不知道的事 – 基础篇 转载 作者:淘宝前端团队(FED)- 化辰 链接:taobaofed.org/blog/2016/07/22/es6-basics/ 序 ES6,或许应该叫 ES ...

  5. python多线程并发_Python进阶记录之基础篇(二十四)

    回顾 在Python进阶记录之基础篇(二十三)中,我们介绍了进程的基本概念以及Python中多进程的基本使用方法.其中,需要重点掌握多进程的创建方法.进程池和进程间的通信.今天我们讲一下Python中 ...

  6. 基础篇9-python基本数据结构-列表

    基础篇9-python基本数据结构-列表 一.列表: 1.有序的集合 2.通过偏移来索引,从而读取数据 3.支持内嵌 a =[[1,2,3],[4,5,6]] 4.可变类型 a[0][1] = 7 二 ...

  7. Linq初级班 Linq To XML体验(基础篇)

    LINQ To XML体验(基础) 这两天开始学习LINQ to XML的知识,我会继续把自己的感想和示例发布给初学者们学习的,一样欢迎高手们多多指点,请勿使用过激语言,针锋相对,我是个初学者,自知还 ...

  8. php 爬虫_Scrapy 爬虫完整案例-基础篇

    1 Scrapy 爬虫完整案例-基础篇 1.1 Scrapy 爬虫案例一 Scrapy 爬虫案例:爬取腾讯网招聘信息 案例步骤: 第一步:创建项目. 在 dos下切换到目录 D:爬虫_scriptsc ...

  9. class括号里的object_Python入门 类class 基础篇

    记住一句话:类是模板,而实例则是根据类创建的对象. 我初学时对类的理解是从类的字面上,可以片面的认为它是一个种类,它是相似特征的抽像,也就是相似的东西,可以把相似特征的事务抽象成一个类.(事务可以是具 ...

  10. MySQL基础篇:子查询

    文章目录 概述 where型子查询 from型子查询 EXISTS型子查询 复制表子查询 概述 在某些情况下,当进行一个查询时,需要的条件或数据要用另一个select语句的结果,这个时候,就要用到** ...

最新文章

  1. linux下将多个文件去除文件头合并_shell命令实现当前目录下多个文件合并为一个文件的方法...
  2. 反应能力测试题_微笑抑郁的表现症状有哪些?你是否正在受微笑抑郁困扰?(内附测试题)...
  3. SQL SERVER 2005 同步复制技术 发布与订阅功能使用说明
  4. javascript本地缓存方案-- 存储对象和设置过期时间
  5. 容器学习 之 容器访问外部网络(十四)
  6. docker集群_使用Docker,Chef和Amazon OpsWorks进行集群范围的Java / Scala应用程序部署...
  7. mysql数据库栏目_MySQL的一些小技巧(持续更新) - mysql数据库栏目
  8. memset()详解
  9. Scala 2.8馆藏图书馆是“历史上最长的遗书”吗? [关闭]
  10. 活动选择问题(贪心)
  11. Toastr 通知提示插件
  12. RapidMiner介绍与实践(二)贝叶斯分类器
  13. matlab 无法终止,Matlab使用xlsread, xlswrite函数导致excel进程无法终止的问题
  14. 玩转华为ENSP模拟器系列 | 配置URPF示例
  15. 王船山的哲思深度:五百年来,真通天人之故者,船山一人而已
  16. 【ChatGPT】多国“围堵”,万人抵制,AI发展的红线到底在哪?
  17. 2的次幂表示(递归求解)
  18. 批量修改文件后缀名(脚本)
  19. 明日开幕|第四届OpenI/O启智开发者大会
  20. Mybatis事务(一)事务管理方式

热门文章

  1. 水平集方法的一个基本框架
  2. lambda-collect-Collectors(Collectors.toCollection,groupingBy,partitioningBy,summingInt,joining)
  3. 程序设计---图书管理系统客户端(优)
  4. Opencv中的imshow函数详解
  5. c语言关于sqrt判断素数原理的理解
  6. 剑三千岛湖服务器是不是维护了,剑网3千岛湖倭寇泡澡怎么完成_剑网3千岛湖倭寇泡澡任务流程_牛游戏网...
  7. 50个有关编程的至理名言
  8. Java进阶 23种设计模式 详解+应用+实例代码
  9. 走秀网OpenXiu2.0的购物袋实现分享
  10. (转)解决“Internet Explorer 无法打开 Internet站点已终止操作”问题