iOS开发中UIWebView 与 WKWebView的基本使用技巧
ios开发中uiwebview 与 wkwebview的基本使用技巧。最近有个需求,是将公司的一个内网的页面嵌套在app中作为一个模块.这不是很简单的webview请求一下就行了么?其实内里大有乾坤.自己也将思路整理一遍。
uiwebview
uiwebview的基本使用方法 :
就这样就已经整整个baidu的页面展示到app上
下面我们看一下webview的属性与方法
uiwebview *webview = [[uiwebview alloc] initwithframe:[uiscreen mainscreen].bounds]; self.view = webview; nsurl *url = [nsurl urlwithstring:@"https://www.baidu.com"]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; [webview loadrequest:request];
uiwebview的层级结构 :
uiwebview的类继承关系
uiwebview的属性 :
// 代理属性 重点需要知道代理方法的使用 @property (nullable, nonatomic, assign) id delegate; // 这个是webview内部的scrollview 只读,但是利用这个属性,设置scrollview的代理,就可以控制整个webview的滚动事件 @property(nonatomic, readonly, strong) uiscrollview *scrollview; // webview的请求,这个属性一般在整个加载完成后才能拿到 @property (nullable, nonatomic, readonly, strong) nsurlrequest *request; // a boolean value indicating whether the receiver can move backward. (read-only) // if yes, able to move backward; otherwise, no. // 如果这个属性为yes,才能后退 @property (nonatomic, readonly, getter=cangoback) bool cangoback; // a boolean value indicating whether the receiver can move forward. (read-only) // if yes, able to move forward; otherwise, no. // 如果这个属性为yes,才能前进 @property (nonatomic, readonly, getter=cangoforward) bool cangoforward; // a boolean value indicating whether the receiver is done loading content. (read-only) // if yes, the receiver is still loading content; otherwise, no. // 这个属性很好用,如果为yes证明webview还在加载数据,所有数据加载完毕后,webview就会为no @property (nonatomic, readonly, getter=isloading) bool loading; //a boolean value determining whether the webpage scales to fit the view and the user can change the scale. //if yes, the webpage is scaled to fit and the user can zoom in and zoom out. if no, user zooming is disabled. the default value is no. // yes代表网页可以缩放,no代表不可以缩放 @property (nonatomic) bool scalespagetofit; // 设置某些数据变为链接形式,这个枚举可以设置如电话号,地址,邮箱等转化为链接 @property (nonatomic) uidatadetectortypes datadetectortypes ns_available_ios(3_0); // iphone safari defaults to no. ipad safari defaults to yes // 设置是否使用内联播放器播放视频 @property (nonatomic) bool allowsinlinemediaplayback ns_available_ios(4_0); // iphone and ipad safari both default to yes // 设置视频是否自动播放 @property (nonatomic) bool mediaplaybackrequiresuseraction ns_available_ios(4_0); // iphone and ipad safari both default to yes // 设置音频播放是否支持ari play功能 @property (nonatomic) bool mediaplaybackallowsairplay ns_available_ios(5_0); // iphone and ipad safari both default to no // 设置是否将数据加载入内存后渲染界面 @property (nonatomic) bool suppressesincrementalrendering ns_available_ios(6_0); // default is yes // 设置用户是否能打开keyboard交互 @property (nonatomic) bool keyboarddisplayrequiresuseraction ns_available_ios(6_0); /* ios7 */ 以后的新特性 // 这个属性用来设置一种模式,当网页的大小超出view时,将网页以翻页的效果展示,枚举如下: @property (nonatomic) uiwebpaginationmode paginationmode ns_available_ios(7_0); typedef ns_enum(nsinteger, uiwebpaginationmode) { uiwebpaginationmodeunpaginated, //不使用翻页效果 uiwebpaginationmodelefttoright, //将网页超出部分分页,从左向右进行翻页 uiwebpaginationmodetoptobottom, //将网页超出部分分页,从上向下进行翻页 uiwebpaginationmodebottomtotop, //将网页超出部分分页,从下向上进行翻页 uiwebpaginationmoderighttoleft //将网页超出部分分页,从右向左进行翻页 }; // this property determines whether certain css properties regarding column- and page-breaking are honored or ignored. // 这个属性决定css的属性分页是可用还是忽略。默认是uiwebpaginationbreakingmodepage @property (nonatomic) uiwebpaginationbreakingmode paginationbreakingmode ns_available_ios(7_0); // 设置每一页的长度 @property (nonatomic) cgfloat pagelength ns_available_ios(7_0); // 设置每一页的间距 @property (nonatomic) cgfloat gapbetweenpages ns_available_ios(7_0); // 获取页数 @property (nonatomic, readonly) nsuinteger pagecount ns_available_ios(7_0);
还有一些属性请详细翻苹果文档
uiwebview的代理方法 :
uiwebview的代理方法 :
uiwebview的代理方法是用的最多的方法,并且一般来说,相对web页面作处理都在这相应的4个方法中
分别解释一下方法的调用情况
// sent before a web view begins loading a frame.请求发送前都会调用该方法,返回no则不处理这个请求 - (bool)webview:(uiwebview *)webview shouldstartloadwithrequest:(nsurlrequest *)request navigationtype:(uiwebviewnavigationtype)navigationtype; // sent after a web view starts loading a frame. 请求发送之后开始接收响应之前会调用这个方法 - (void)webviewdidstartload:(uiwebview *)webview; // sent after a web view finishes loading a frame. 请求发送之后,并且服务器已经返回响应之后调用该方法 - (void)webviewdidfinishload:(uiwebview *)webview; // sent if a web view failed to load a frame. 网页请求失败则会调用该方法 - (void)webview:(uiwebview *)webview didfailloadwitherror:(nullable nserror *)error;
uiwebview的对象方法
uiwebview的对象方法
// 加载data数据创建一个webview - (void)loaddata:(nsdata *)data mimetype:(nsstring *)mimetype textencodingname:(nsstring *)encodingname baseurl:(nsurl *)baseurl // 加载本地html创建一个webview - (void)loadhtmlstring:(nsstring *)string baseurl:(nsurl *)baseurl // 加载一个请求创建一个webview - (void)loadrequest:(nsurlrequest *)request // 刷新网页 - (void)reload; // 停止网页加载内容 - (void)stoploading; // 后退 - (void)goback; // 前进 - (void)goforward; // 执行js方法 - (nsstring *)stringbyevaluatingjavascriptfromstring:(nsstring *)script
wkwebview
wkwebview
wkwebview的简介 :
wkwebview的简介 :
从文档中可以看到,这个是ios8之后新增的一个类,也是苹果推崇的一个新的类
wkwebview的类层级结构
wkwebview的基本使用方法 :
wkwebview的基本使用方法 :
其实和uiwebview的用法没什么区别
但是wkwebview相对于uiwebview强大了很多,内存的消耗相对少了,所提供的接口也丰富了。
推荐使用
多了一部操作就是需要包含webkit框架
@import webkit
wkwebview *webview = [[wkwebview alloc] initwithframe:[uiscreen mainscreen].bounds]; self.view = webview; nsurl *url = [nsurl urlwithstring:@"https://www.baidu.com"]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; [webview loadrequest:request];
wkwebview的属性 :
wkwebview的属性 :
// uiwebview 中会自动保存cookie,如果登录了一次下次再次进入的时候,会记住登录状态 // 在wkwebview中,新增一个configuration属性, configuration 让wkwebview知道登录状态, // configuration 可以通过已有的cookie进行设置,也可以通过保存上一次的configuration进行设置 // wkwebviewconfiguration类中也有一些相应的属性 @property (nonatomic, readonly, copy) wkwebviewconfiguration *configuration; // the methods of the wknavigationdelegate protocol help you track the progress of the web site's main frame navigations and decide load policy for main frame and subframe navigations. // wkwebview中,加入了网站导航的概念,这个对象决定主框架导航加载方法协议。 @property (nullable, nonatomic, weak) id navigationdelegate; // the wkuidelegate class provides methods for presenting native user interface elements on behalf of a webpage. // wkwebview中,加入了网站窗口的概念,这个对象决了webview窗口的一些方法协议。 @property (nullable, nonatomic, weak) id uidelegate; a wkbackforwardlist object is a list of webpages previously visited in a web view that can be reached by going back or forward. // wkwebview中,加入了网站列表的概念,这个webbackforwardlist对象是以前在web视图访问的网页,可以通过去后退或前进 @property (nonatomic, readonly, strong) wkbackforwardlist *backforwardlist;
还有很多方法,同样可以查文档看到
wkwebview的代理方法 :
wkwebview的代理方法 :
有一些方法和uiwebview是基本一直的,但是因为返回了navigation,所能用到的属性多了很多,另外多了一些方法,将请求与相应的整个过程
- (void)webviewwebcontentprocessdidterminate:(wkwebview *)webview{ nslog(@"webviewwebcontentprocessdidterminate: 当web视图的网页内容被终止时调用。"); } - (void)webview:(wkwebview *)webview didfinishnavigation:(null_unspecified wknavigation *)navigation { [uiapplication sharedapplication].networkactivityindicatorvisible = no; nslog(@"webview:didfinishnavigation: 响应渲染完成后调用该方法 webview : %@ -- navigation : %@ \n\n",webview,navigation); } - (void)webview:(wkwebview *)webview didstartprovisionalnavigation:(null_unspecified wknavigation *)navigation { [uiapplication sharedapplication].networkactivityindicatorvisible = yes; nslog(@"webview:didstartprovisionalnavigation: 开始请求 \n\n"); } - (void)webview:(wkwebview *)webview didcommitnavigation:(wknavigation *)navigation { nslog(@"webview:didcommitnavigation: 响应的内容到达主页面的时候响应,刚准备开始渲染页面应用 \n\n"); } // error - (void)webview:(wkwebview *)webview didfailprovisionalnavigation:(wknavigation *)navigation witherror:(nserror *)error { // 类似 uiwebview 的- webview:didfailloadwitherror: nslog(@"webview:didfailprovisionalnavigation:witherror: 启动时加载数据发生错误就会调用这个方法。 \n\n"); } - (void)webview:(wkwebview *)webview didfailnavigation:(wknavigation *)navigation witherror:(nserror *)error{ nslog(@"webview:didfailnavigation: 当一个正在提交的页面在跳转过程中出现错误时调用这个方法。 \n\n"); } - (void)webview:(wkwebview *)webview decidepolicyfornavigationaction:(wknavigationaction *)navigationaction decisionhandler:(void (^)(wknavigationactionpolicy))decisionhandler{ nslog(@"请求前会先进入这个方法 webview:decidepolicyfornavigationactiondecisionhandler: %@ \n\n ",navigationaction.request); decisionhandler(wknavigationactionpolicyallow); } - (void)webview:(wkwebview *)webview decidepolicyfornavigationresponse:(wknavigationresponse *)navigationresponse decisionhandler:(void (^)(wknavigationresponsepolicy))decisionhandler{ nslog(@"返回响应前先会调用这个方法 并且已经能接收到响应webview:decidepolicyfornavigationresponse:decisionhandler: response?%@ \n\n",navigationresponse.response); decisionhandler(wknavigationresponsepolicyallow); } - (void)webview:(wkwebview *)webview didreceiveserverredirectforprovisionalnavigation:(wknavigation *)navigation{ nslog(@"webview:didreceiveserverredirectforprovisionalnavigation: 重定向的时候就会调用 \n\n"); }
wkwebview的对象方法 :
wkwebview的对象方法 :
这些方法,基本上和uiwebview中的使用用法是一致的,所以
// 这是加载网页最常用的一种方式,通过一个网页url来加载一个wkwebview,这个url可以是远程的也可以是本地的,例如我加载百度的主页 - (nullable wknavigation *)loadrequest:(nsurlrequest *)request; // 根据一个文件,加载一个wkwebview - (nullable wknavigation *)loadfileurl:(nsurl *)url allowingreadaccesstourl:(nsurl *)readaccessurl ns_available(10_11, 9_0); // 这个方法需要将html文件读取为字符串从而加载为wkwebview,其中baseurl是我们自己设置的一个路径,用于寻找html文件中引用的图片等素材。 - (nullable wknavigation *)loadhtmlstring:(nsstring *)string baseurl:(nullable nsurl *)baseurl; // 这个方式使用的比较少,但也更加*,其中data是文件数据,mimetype是文件类型,characterencodingname是编码类型,baseurl是素材资源路径 - (nullable wknavigation *)loaddata:(nsdata *)data mimetype:(nsstring *)mimetype characterencodingname:(nsstring *)characterencodingname baseurl:(nsurl *)baseurl ns_available(10_11, 9_0);
基本使用
基本使用
下面会总结一些我在开发过程中遇到的坑,和解决问题的一些思路,不过在此之前我发现,如果要webview玩得好,有以下几点的只是也需要掌握好,因为我认为在h5崛起的今天,源生app和h5的交互之间会产生比较大改变,而且源生与h5之间的混编,越来越被重视.所以 :
源生技术,特别是有关于webview这一块的api要非常熟练,js语法, js的语法需要熟练,特别是操作document的几个常用js,标签需要用得滚瓜烂熟.要非常了解网络请求 - 响应的机制,理解请求头,响应头,等等.http的整套协议
需求一 : 展示一个网页,但是需要隐藏一部分页面
需求一 : 展示一个网页,但是需要隐藏一部分页面
首先看看百度的页面,这是用chrome打开的开发者模式
基本界面组成如下,基本使用用法请详情百度,这里不作介绍
假设现在想将这个logo由网页开始加载就去掉
百度的logo就是一个p套着一个image标签
- (void)webviewdidfinishload:(uiwebview *)webview { // 在html标签都加载完成后,开始处理html标签,调用js,操作document [webview stringbyevaluatingjavascriptfromstring:@"document.getelementbyid('plus-card').remove();"]; }
就这样, logo标签就被去掉了,思路就是等html加载完成后,操作js从而操作document标签从而改变整个html页面的应用,下图是去掉整个body主题内容后的结果
另外还可以将一段函数封装到里面,执行函数,原理是通过stringbyevaluatingjavascriptfromstring将js函数写进head标签中,然后再调用该函数
// 自定义editmylogo函数 [webview stringbyevaluatingjavascriptfromstring:@"var script = document.createelement('script');" "script.type = 'text/javascript';" "script.text = \"function editmylogo() { " "var logo = document.getelementbyid('logo');" "logo.innerhtml= logo.innerhtml + '这是我自己定义的名字';" "var imglist = logo.getelementsbytagname('img');" "for (i=0 ; i < imglist.length ; i++ ){" "imglist[i].src = 'https://pic.to8to.com/attch/day_160218/20160218_d968438a2434b62ba59dh7q5kezts6oh.png';" "}" "}\";" "document.getelementsbytagname('head')[0].appendchild(script);"]; // 执行editmylogo函数 [webview stringbyevaluatingjavascriptfromstring:@"editmylogo();"];
效果如下 :
有几点问题,这种操作是在webviewdidfinishload方法下进行的,webviewdidfinishload方法是webview的document已经渲染好后,再去处理这个这个页面.
你会发现有时候会出现一些闪屏现象,原因是渲染过后,内部处理js代码后,页面会再渲染一次资源浪费,假设这边的需求只需要显示10%的内容,却要加载100%的内容,不过这一方面还需要网页端作出很好的适配某些时候,js会失效,不知道什么原因,有些时候自定义加载的js的方法并没有执行到.等于内容并没有屏蔽等等..
需求二 : 怎样处理403,404的情况 ?
需求二 : 怎样处理403,404的情况 ?
@property (nonatomic, assign) bool ispost; // 定义一个变量 // 每一个请求开始发送前都会调用这个方法 // 1, 定义一个全局变量currentrequest,用作保存当前的请求 // 2, 将请求转换成data,然后处理data再将data作为请求数据再次请求 - (bool)webview:(uiwebview *)webview shouldstartloadwithrequest:(nsurlrequest *)request navigationtype:(uiwebviewnavigationtype)navigationtype{ if (!_ispost) { nshttpurlresponse *response = nil; nsdata *data = [nsurlconnection sendsynchronousrequest:request returningresponse:&response error:nil]; if (response.statuscode == 404) { // 这里处理 404 代码 } else if (response.statuscode == 403) { // 这里处理 403 代码 } else { _ispost = true; [webview loaddata:data mimetype:@"text/html" textencodingname:@"nsutf8stringencoding" baseurl:[request url]]; } return no; }else{ nslog(@"\n\n shouldstartloadwithrequest请求准备 -- %@ \n\n ",request); _ispost = no; return yes; } }
需求一 : 进一步改进
需求一 : 进一步改进
在处理html这里,将你想隐藏的页面,加上 display:none 属性,
或者,将整段html标签去掉.
上一篇: 教务也是操碎了心
下一篇: 看儿子抓耳挠腮在写作文
推荐阅读