Hybrid App 应用开发中 9 个必备知识点复习。附资料分享


  一、iOS 平台中 UIWebView 与 WKWebView 有什么区别?

  参考文章:[《UIWebView与WKWebView》]

  UIWebView 是苹果继承于 UIView 封装的一个加载 web 内容的类,它可以加载任何远端的web数据展示在你的页面上,你可以像浏览器一样前进后退刷新等操作。

  不过苹果在 iOS8 以后推出了 WKWebView 来加载 Web,并应用于 iOS 和 OSX 中,它取代了 UIWebView 和 WebView ,在两个平台上支持同一套 API。

  它脱离于 UIWebView 的设计,将原本的设计拆分成14个类,和3个代理协议,虽然是这样但是了解之后其实用法比较简单,依照职责单一的原则,每个协议做的事情根据功能分类。

  Hybrid App 应用开发中 9 个必备知识点复习。附资料分享

  WKWebView 与 UIWebView 的区别:

  WKWebView 的内存远远没有 UIWebView 的开销大,而且没有缓存;

  WKWebView 拥有高达 60FPS 滚动刷新率及内置手势;WKWebView 支持了更多的 HTML5 特性;WKWebView 高效的 app 和 web 信息交换通道;WKWebView 允许 JavaScript 的 Nitro 库加载并使用, UIWebView 中限制了;WKWebView 目前缺少关于页码相关的 API;WKWebView 提供加载网页进度的属性;WKWebView 使用 Safari 相同的 JavaScript 引擎;WKWebView 增加加载进度属性: estimatedProgress ;WKWebView 不支持页面缓存,需要自己注入 cookie , 而 UIWebView 是自动注入 cookie ;WKWebView 无法发送 POST 参数问题;WKWebView 可以和js直接互调函数,不像 UIWebView 需要第三方库 WebViewJavascriptBridge 来协助处理和 js 的交互;

  注意:

  大多数App需要支持 iOS7 以上的版本,而 WKWebView 只在 iOS8 后才能用,所以需要一个兼容性方案,既 iOS7 下用 UIWebView , iOS8 后用 WKWebView 。但是目前 IOS10 以下的系统以及很少了,

  小结:

  WKWebView 相较于 UIWebView 在整体上有较大的提升,满足 iOS 上面使用同一套控件的功能,同时对整个内存的开销以及滚动刷新率和 JS 交互做了优化的处理。

  依据职责单一原则,拆分成了三个协议去实现 WebView 的响应,解耦了 JS 交互和加载进度的响应处理。

  WKWebView 没有做缓存处理,所以对网页需要缓存的加载性能要求没那么高的还是可以考虑 UIWebView 。

  二、WKWebView 有哪一些坑?

  参考文章:[《WKWebView 那些坑》]

  1. WKWebView 白屏问题

  WKWebView 实际上是个多进程组件,这也是它加载速度更快,内存暂用更低的原因。

  在 UIWebView 上当内存占用太大的时候,App Process 会 crash;而在 WKWebView 上当总体的内存占用比较大的时候,WebContent Process 会 crash,从而出现白屏现象。

  解决办法:

  借助 WKNavigtionDelegate

  当 WKWebView 总体内存占用过大,页面即将白屏的时候,系统会调用上面的回调函数,我们在该函数里执行[webView reload](这个时候 webView.URL 取值尚不为 nil)解决白屏问题。在一些高内存消耗的页面可能会频繁刷新当前页面,H5侧也要做相应的适配操作。

  检测 webView.title 是否为空

  并不是所有 H5 页面白屏的时候都会调用上面的回调函数,比如,最近遇到在一个高内存消耗的 H5 页面上 present 系统相机,拍照完毕后返回原来页面的时候出现白屏现象(拍照过程消耗了大量内存,导致内存紧张,WebContent Process 被系统挂起),但上面的回调函数并没有被调用。在 WKWebView 白屏的时候,另一种现象是 webView.titile 会被置空, 因此,可以在 viewWillAppear的时候检测 webView.title 是否为空来 reload 页面。

  2. WKWebView Cookie 问题

  WKWebView Cookie 问题在于 WKWebView 发起的请求不会自动带上存储于 NSHTTPCookieStorage 容器中的 Cookie,而在 UIWebView 会自动带上 Cookie。

  原因是:

  WKWebView 拥有自己的私有存储,不会将 Cookie 存入到标准的 Cookie 容器 NSHTTPCookieStorage 中。

  实践发现 WKWebView 实例其实也会将 Cookie 存储于 NSHTTPCookieStorage 中,但存储时机有延迟,在 iOS8上,当页面跳转的时候,当前页面的 Cookie 会写入 NSHTTPCookieStorage 中,而在 iOS10 上,JS 执行 document.cookie 或服务器 set-cookie 注入的 Cookie 会很快同步到 NSHTTPCookieStorage 中,FireFox 工程师曾建议通过 resetWKProcessPool 来触发 Cookie 同步到 NSHTTPCookieStorage 中,实践发现不起作用,并可能会引发当前页面 session cookie丢失等问题。

  解决办法1:

  WKWebViewloadRequest 前,在 request header 中设置 Cookie, 解决首个请求 Cookie 带不上的问题;

  解决办法2:

  通过 document.cookie 设置 Cookie 解决后续页面(同域) Ajax``、iframe 请求的 Cookie 问题;(注意: document.cookie() 无法跨域设置 cookie)。

  3. WKWebView loadRequest 问题

  在 WKWebView 上通过 loadRequest 发起的 post 请求 body 数据会丢失,同样是由于进程间通信性能问题, HTTPBody 字段被丢弃。

  4. WKWebView NSURLProtocol问题

  WKWebView 在独立于 app 进程之外的进程中执行网络请求,请求数据不经过主进程,因此,在 WKWebView 上直接使用 NSURLProtocol 无法拦截请求。

  解决办法:

  由于 WKWebView 在独立进程里执行网络请求。一旦注册 http(s)scheme 后,网络请求将从 NetworkProcess 发送到 AppProcess,这样 NSURLProtocol 才能拦截网络请求。在 webkit2 的设计里使用 MessageQueue 进行进程之间的通信,Network Process 会将请求 encode 成一个 Message,然后通过 IPC 发送给 AppProcess。出于性能的原因, encode 的时候 HTTPBody 和 HTTPBodyStream 这两个字段会被丢弃掉了。

  5. WKWebView 页面样式问题

  在 WKWebView 适配过程中,我们发现部分 H5 页面元素位置向下偏移或被拉伸变形,追踪后发现主要是 H5 页面高度值异常导致。

  解决办法:

  调整 WKWebView 布局方式,避免调整 webView.scrollView.contentInset 。实际上,即便在UIWebView 上也不建议直接调整 webView.scrollView.contentInset 的值,这确实会带来一些奇怪的问题。如果某些特殊情况下非得调整 contentInset 不可的话,可以通过下面方式让H5页面恢复正常显示。

  6. WKWebView 截屏问题

  WKWebView 下通过 -[CALayer renderInContext:]实现截屏的方式失效,需要通过以下方式实现截屏功能: