iOS-WKWebView的使用
参考文章:
wk时苹果在ios8.0之后推出的控件,相比于uiwebview:
- 内存消耗少;
- 解决了网页加载时的内存泄漏问题;
- 与html页面的交互更方便;
- 总之,其性能比uiwebview好很多。
使用时,首先要添加头文件:
#import <webkit/webkit.h>
简单创建一个wkwebview:
self.iwkwebview = [[wkwebview alloc]initwithframe:cgrectmake(0, 64, [uiscreen mainscreen].bounds.size.width, [uiscreen mainscreen].bounds.size.height-64)]; //此处协议下面会讲到 self.iwkwebview.navigationdelegate = self; self.iwkwebview.uidelegate = self; self.iwkwebview.allowsbackforwardnavigationgestures = yes; nsurl *url = [nsurl urlwithstring:@"https://www.baidu.com"]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; [self.iwkwebview loadrequest:request]; [self.view addsubview:self.iwkwebview];
基本用法和uiwebview差不多。
这里介绍几个主要的类:
- wkwebview
-
wkwebviewconfiguration
-
wkpreferences
-
wkusercontentcontroller
-
wkwebsitedatastore
1. wkwebview:
常用属性:
// 导航代理 @property (nullable, nonatomic, weak) id <wknavigationdelegate> navigationdelegate; // ui代理 @property (nullable, nonatomic, weak) id <wkuidelegate> uidelegate; // 页面标题, 一般使用kvo动态获取 @property (nullable, nonatomic, readonly, copy) nsstring *title; // 页面加载进度, 一般使用kvo动态获取 @property (nonatomic, readonly) double estimatedprogress; // 可返回的页面列表, 已打开过的网页, 有点类似于navigationcontroller的viewcontrollers属性 @property (nonatomic, readonly, strong) wkbackforwardlist *backforwardlist; // 页面url @property (nullable, nonatomic, readonly, copy) nsurl *url; // 页面是否在加载中 @property (nonatomic, readonly, getter=isloading) bool loading; // 是否可返回 @property (nonatomic, readonly) bool cangoback; // 是否可向前 @property (nonatomic, readonly) bool cangoforward; // wkwebview继承自uiview, 所以如果想设置scrollview的一些属性, 需要对此属性进行配置 @property (nonatomic, readonly, strong) uiscrollview *scrollview; // 是否允许手势左滑返回上一级, 类似导航控制的左滑返回 @property (nonatomic) bool allowsbackforwardnavigationgestures; //自定义useragent, 会覆盖默认的值 ,ios 9之后有效 @property (nullable, nonatomic, copy) nsstring *customuseragent
常用方法:
// 带配置信息的初始化方法 // configuration 配置信息 - (instancetype)initwithframe:(cgrect)frame configuration:(wkwebviewconfiguration *)configuration // 加载请求 - (nullable wknavigation *)loadrequest:(nsurlrequest *)request; // 加载html - (nullable wknavigation *)loadhtmlstring:(nsstring *)string baseurl:(nullable nsurl *)baseurl; // 返回上一级 - (nullable wknavigation *)goback; // 前进下一级, 需要曾经打开过, 才能前进 - (nullable wknavigation *)goforward; // 刷新页面 - (nullable wknavigation *)reload; // 根据缓存有效期来刷新页面 - (nullable wknavigation *)reloadfromorigin; // 停止加载页面 - (void)stoploading; // 执行javascript代码 - (void)evaluatejavascript:(nsstring *)javascriptstring completionhandler:(void (^ _nullable)(_nullable id, nserror * _nullable error))completionhandler;
2. wkwebviewconfiguration:配置信息
可以用配置信息来初始化wkwebview.
属性有:
//关于网页的设置 @property (nonatomic, strong) wkpreferences *preferences; //javascript与原生交互的桥梁 @property (nonatomic, strong) wkusercontentcontroller *usercontentcontroller; //提供了网站所能使用的数据类型 @property (nonatomic, strong) wkwebsitedatastore *websitedatastore api_available(macosx(10.11), ios(9.0)); //是否允许播放媒体文件 @property (nonatomic) bool allowsairplayformediaplayback api_available(macosx(10.11), ios(9.0)); //是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放 @property (nonatomic) bool allowsinlinemediaplayback; //需要用户允许才能播放的媒体类型 @property (nonatomic) wkaudiovisualmediatypes mediatypesrequiringuseractionforplayback api_available(macosx(10.12), ios(10.0));
2.1 wkpreference:
wkpreferences *preference = [[wkpreferences alloc]init]; //最小字体大小 preference.minimumfontsize = 0; //是否支持javascript,默认yes preference.javascriptenabled = yes; //是否允许不经过用户交互由javascript自动打开窗口 preference.javascriptcanopenwindowsautomatically = yes;
2.2 wkusercontentcontroller
// 注入javascript与原生交互协议 // js 端可通过 window.webkit.messagehandlers..postmessage() 发送消息 - (void)addscriptmessagehandler:(id <wkscriptmessagehandler>)scriptmessagehandler name:(nsstring *)name; // 移除注入的协议, 在deinit方法中调用 - (void)removescriptmessagehandlerforname:(nsstring *)name; // 通过wkuserscript注入需要执行的javascript代码 - (void)adduserscript:(wkuserscript *)userscript; // 移除所有注入的javascript代码 - (void)removealluserscripts;
使用wkusercontentcontroller注入的交互协议, 需要遵循wkscriptmessagehandler协议, 在其协议方法中获取javascript端传递的事件和参数:
- (void)usercontentcontroller:(wkusercontentcontroller *)usercontentcontroller didreceivescriptmessage:(wkscriptmessage *)message; wkscriptmessage包含了传递的协议名称及参数, 主要从下面的属性中获取: // 协议名称, 即上面的add方法传递的name @property (nonatomic, readonly, copy) nsstring *name; // 传递的参数 @property (nonatomic, readonly, copy) id body;
2.3 wkwebsitedatastore
wkwebsitedatastore 提供了网站所能使用的数据类型,包括 cookies,硬盘缓存,内存缓存活在一些websql的数据持久化和本地持久化。可通过 wkwebviewconfiguration类的属性 websitedatastore 进行相关的设置。wkwebsitedatastore相关的api也比较简单:
// 默认的data store + (wkwebsitedatastore *)defaultdatastore; // 如果为webview设置了这个data store,则不会有数据缓存被写入文件 // 当需要实现隐私浏览的时候,可使用这个 + (wkwebsitedatastore *)nonpersistentdatastore; // 是否是可缓存数据的,只读 @property (nonatomic, readonly, getter=ispersistent) bool persistent; // 获取所有可使用的数据类型 + (nsset<nsstring *> *)allwebsitedatatypes; // 查找指定类型的缓存数据 // 回调的值是wkwebsitedatarecord的集合 - (void)fetchdatarecordsoftypes:(nsset<nsstring *> *)datatypes completionhandler:(void (^)(nsarray<wkwebsitedatarecord *> *))completionhandler; // 删除指定的纪录 // 这里的参数是通过上面的方法查找到的wkwebsitedatarecord实例获取的 - (void)removedataoftypes:(nsset<nsstring *> *)datatypes fordatarecords:(nsarray<wkwebsitedatarecord *> *)datarecords completionhandler:(void (^)(void))completionhandler; // 删除某时间后修改的某类型的数据 - (void)removedataoftypes:(nsset<nsstring *> *)websitedatatypes modifiedsince:(nsdate *)date completionhandler:(void (^)(void))completionhandler; // 保存的http cookies @property (nonatomic, readonly) wkhttpcookiestore *httpcookiestore
datatypes:
// 硬盘缓存 wkwebsitedatatypediskcache, // html离线web应用程序缓存 wkwebsitedatatypeofflinewebapplicationcache, // 内存缓存 wkwebsitedatatypememorycache, // 本地缓存 wkwebsitedatatypelocalstorage, // cookies wkwebsitedatatypecookies, // html会话存储 wkwebsitedatatypesessionstorage, // indexeddb 数据库 wkwebsitedatatypeindexeddbdatabases, // websql 数据库 wkwebsitedatatypewebsqldatabases
datarecord:
// 展示名称, 通常是域名 @property (nonatomic, readonly, copy) nsstring *displayname; // 包含的数据类型 @property (nonatomic, readonly, copy) nsset<nsstring *> *datatypes;
关于此类的简单使用:
1.删除指定时间的所有类型数据
nsset *websitedatatypes = [wkwebsitedatastore allwebsitedatatypes]; nsdate *datefrom = [nsdate datewithtimeintervalsince1970:0]; [[wkwebsitedatastore defaultdatastore] removedataoftypes:websitedatatypes modifiedsince:datefrom completionhandler:^{ // done nslog(@"释放"); }];
2.查找删除
wkwebsitedatastore *datastore = [wkwebsitedatastore defaultdatastore]; [datastore fetchdatarecordsoftypes:[wkwebsitedatastore allwebsitedatatypes] completionhandler:^(nsarray<wkwebsitedatarecord *> * _nonnull records) { for (wkwebsitedatarecord *record in records) { [datastore removedataoftypes:record.datatypes fordatarecords:@[record] completionhandler:^{ // done }]; } }];
3.查找删除特定的内容
wkwebsitedatastore *datastore = [wkwebsitedatastore defaultdatastore]; [datastore fetchdatarecordsoftypes:[wkwebsitedatastore allwebsitedatatypes] completionhandler:^(nsarray<wkwebsitedatarecord *> * _nonnull records) { for (wkwebsitedatarecord *record in records) { if ([record.displayname isequaltostring:@"baidu"]) { [datastore removedataoftypes:record.datatypes fordatarecords:@[record] completionhandler:^{ // done }]; } } }];
wknavigationdelegate:
#pragma mark - wknavigationdelegate //请求加载之前,决定是否跳转 - (void)webview:(wkwebview *)webview decidepolicyfornavigationaction:(wknavigationaction *)navigationaction decisionhandler:(void (^)(wknavigationactionpolicy))decisionhandler{ nslog(@"加载前允许跳转"); decisionhandler(wknavigationactionpolicyallow); } //开始加载时调用 - (void)webview:(wkwebview *)webview didstartprovisionalnavigation:(null_unspecified wknavigation *)navigation{ nslog(@"开始加载"); } //收到响应开始加载后,决定是否跳转 - (void)webview:(wkwebview *)webview decidepolicyfornavigationresponse:(wknavigationresponse *)navigationresponse decisionhandler:(void (^)(wknavigationresponsepolicy))decisionhandler{ nslog(@"收到响应后允许跳转"); decisionhandler(wknavigationresponsepolicyallow); } //内容开始返回时调用 - (void)webview:(wkwebview *)webview didcommitnavigation:(null_unspecified wknavigation *)navigation{ nslog(@"开始返回内容"); } //加载完成时调用 - (void)webview:(wkwebview *)webview didfinishnavigation:(null_unspecified wknavigation *)navigation{ nslog(@"加载完成"); self.title = webview.title; } //加载失败调用 - (void)webview:(wkwebview *)webview didfailprovisionalnavigation:(null_unspecified wknavigation *)navigation witherror:(nserror *)error{ nslog(@"加载失败"); } //收到服务器重定向请求后调用 - (void)webview:(wkwebview *)webview didreceiveserverredirectforprovisionalnavigation:(null_unspecified wknavigation *)navigation{ nslog(@"服务器重定向"); } //当main frame最后下载数据失败时,会回调 - (void)webview:(wkwebview *)webview didfailnavigation:(null_unspecified wknavigation *)navigation witherror:(nserror *)error{ nslog(@"返回内容发生错误"); } //用于授权验证的api,与afn、uiwebview的授权验证api是一样的 - (void)webview:(wkwebview *)webview didreceiveauthenticationchallenge:(nsurlauthenticationchallenge *)challenge completionhandler:(void (^)(nsurlsessionauthchallengedisposition disposition, nsurlcredential * _nullable credential))completionhandler{ completionhandler(nsurlsessionauthchallengeperformdefaulthandling,nil); } //当web content处理完成时,会回调 - (void)webviewwebcontentprocessdidterminate:(wkwebview *)webview api_available(macosx(10.11), ios(9.0)){ nslog(@"webcontent完成"); }
这里放一个完整的wkwebview例子,仅供参考:
//初始化wkpreferences,并设置相关属性 wkpreferences *preference = [[wkpreferences alloc]init]; //初始化wkusercontentcontroller,并设置相关属性 wkusercontentcontroller *usercontroller = [[wkusercontentcontroller alloc]init]; // 添加在js中操作的对象名称,通过该对象来向web view发送消息 // js 端可通过 window.webkit.messagehandlers..postmessage() 发送消息 // <script type="text/javascript"> // function clickbtn(){ // var dict = {"name":"tom","age":"20"}; // window.webkit.messagehandlers.jssendtooc.postmessage(dict); // } // </script> [usercontroller addscriptmessagehandler:self name:@"jssendtooc"]; //初始化wkwebsitedatastore,并设置相关属性 wkwebsitedatastore *datastore = [wkwebsitedatastore defaultdatastore]; // 如果为webview设置了这个data store,则不会有数据缓存被写入文件 // 当需要实现隐私浏览的时候,可使用这个 // wkwebsitedatastore *datastore = [wkwebsitedatastore nonpersistentdatastore]; //配置信息 wkwebviewconfiguration *configuration = [[wkwebviewconfiguration alloc]init]; configuration.preferences = preference; configuration.usercontentcontroller = usercontroller; configuration.websitedatastore = datastore; self.iwkwebview = [[wkwebview alloc]initwithframe:cgrectmake(0, 64, [uiscreen mainscreen].bounds.size.width, [uiscreen mainscreen].bounds.size.height-64) configuration:configuration]; self.iwkwebview.navigationdelegate = self; self.iwkwebview.uidelegate = self; self.iwkwebview.allowsbackforwardnavigationgestures = yes; nsurl *url = [nsurl urlwithstring:@"https://www.baidu.com"]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; [self.iwkwebview loadrequest:request]; [self.view addsubview:self.iwkwebview];
上一篇: 线程通信