iOS 加载网络页面白屏问题和参考解决办法

2019-01-03  本文已影响0人  魔力双鱼

前言

白屏问题iOS开发中最令人头疼的问题之一。WKWebView随iOS8 推出已有4年了,解决了很多UIWebView的问题,比如内存泄漏、加载速度慢、不太兼容iOS10, iOS11等。Apple Support iOS版本的市场分布情况,绝大部分的设备都是iOS8 以上,iOS开始强制使用HTTPS请求,但还有部分公司的APP支持iOS7和HTTP请求,要赶上时代的步伐啊!

WKWebView的特点

HTTPS的特点

一. URL网址无效或含有中文字符(入门级错误)

APP内展示URL的来源主要是后端返回或前端拼接,甚至前端hardcode,网址存在不确定性,可能是无效或含有中文字符。大部分浏览器是能打开带有中文字符的网络地址,但是iOS的内嵌网页加加载框架无论是UIWebView还是WKWebView,都不能打开带有中文字符的网络地址,需要先对地址字符串做UTF8转码。参考代码:

urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

二. HTTP请求问题

在iOS9 中,系统将原http协议改成了默认https协议,使用 TLS1.2 SSL加密请求数据。可以通过升级支持HTTPS协议请求,也可以通过设置强制使用HTTP请求。在Info.plist中添加NSAppTransportSecurity类型Dictionary。在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES。部分第三方应用不支持HTTPS,需要在在info.list设置HTTP请求白名单,允许部分请求可以是HTTP。参考代码:

<key>LSApplicationQueriesSchemes</key>  
      <array>           
<!-- 微信 URL Scheme 白名单-->     
         <string>wechat</string>   
         <string>weixin</string>   
       </array>

三. HTTPS 请求,未实现证书认证代理导致页面不加载的问题

如果是HTTPS 请求,需要在WKWebView 的 WKNavigationDelegate 中的一个代理方法 中实现获取服务器认证的逻辑,最后返回给服务端。 这个问题常常出现在客户端无法获得安全认证的时候(没有证书,或者是自建证书),比如说https://www.apple.com/cn 是默认的苹果中国的地址,但是 https://www.apple.com.cn 也是可以访问的(会自动跳转到 https://www.apple.com/cn ) ,只是在Safari 的安全认证中通不过,我们需要在代理方法中通过服务端给的验证方式创建一个凭证,然后继续申请访问。比如在Safari 浏览器中第一次访问时就会弹出对话框,点击继续后就可以继续访问。通过实现以下代理即可解决

func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
{  // 判断服务器采用的验证方法
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        if challenge.previousFailureCount == 0 {
            // 如果没有错误的情况下 创建一个凭证,并使用证书
            let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            completionHandler(.UseCredential, credential)
        } else {
            // 验证失败,取消本次验证
            completionHandler(.CancelAuthenticationChallenge, nil)
        }
    } else {
        completionHandler(.CancelAuthenticationChallenge, nil)
    }
}

四. iOS 8.0 - iOS 8.2 偶尔白屏问题

这个是WKWebView 刚推出时的Bug,偶尔会出现白屏,如果想避免这种问题,只能通过版本号判断,小于8.2的系统暂时使用UIWebView。

五. 滚动组件嵌套,未能刷新页面

在UITableView或UICollectionView中嵌套WKWebView引起的,可以试着将UITableView或UICollectionView中替换为UIScrollview 。可能是因为页面滚动后没有正常的调用 WKWebView 的 _updateVisibleContentRects 方法刷新需要渲染的内容导致的。

六. 硬件内存不足、进程崩溃

在 UIWebView 上当内存占用太大的时候,App Process 会 crash;而在 WKWebView 上当总体的内存占用比较大的时候,WebContent Process 会 crash,从而出现白屏现象。在 WKWebView 中加载下面的测试链接可以稳定重现白屏现象:

http://people.mozilla.org/~rnewman/fennec/mem.html

这个时候 WKWebView.URL 会变为 nil, 简单的 reload 刷新操作已经失效,对于一些长驻的H5页面影响比较大。参考解决方案:

1、借助 WKNavigtionDelegate

iOS 9以后 WKNavigtionDelegate 新增了一个回调函数:

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

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

2、检测 webView.title 是否为空

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

上一篇 下一篇

猜你喜欢

热点阅读