苹果放弃UIWebView后,公司项目已经全面采用高性能和高刷新的 WKWebView,但是加载网页过程中还是经常出现白屏的现象,且现有API协议捕获不到这种异常。造成用户体验极差。
针对业务场景需求,考虑采用字节跳动团队提出的 WebView 优化技术方案。在合适的加载时机对当前 WebView 可视区域截图,并对此快照进行像素点遍历,如果非白屏颜色的像素点超过一定的阈值,认定其为非白屏,反之重新加载请求。实现加载白屏检测。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| import UIKit import WebKit
extension WKWebView { enum WebLoadingStatus{ case normal case error } func judgeLoadingStatus(webView: WKWebView?, completion: ((_ status: WebLoadingStatus) -> Void)?) { if #available(iOS 11.0, *) { guard let webView = webView else { return } let window = UIApplication.shared.keyWindow guard let window = window else { return } let webViewRect = webView.convert(webView.bounds, to: window) let shotConfiguration = WKSnapshotConfiguration() shotConfiguration.rect = CGRect(x: webViewRect.origin.x, y: webViewRect.origin.y, width: webViewRect.size.width, height: webViewRect.size.height) webView.takeSnapshot(with: shotConfiguration) { [weak self] (image, error) in guard let self = self, let image = image else { return } let scaleImage = self.scaleImage(image: image) let isWhiteScreen = self.searchEveryPixel(image: scaleImage) if isWhiteScreen { completion?(.error) } else { completion?(.normal) } } } } private func searchEveryPixel(image: UIImage) -> Bool { let cgImage = image.cgImage let width: size_t = cgImage?.width ?? 0 let height: size_t = cgImage?.height ?? 0 let dataProvider = cgImage?.dataProvider let data = dataProvider?.data let buffer: UnsafePointer<UInt8> = CFDataGetBytePtr(data) var whiteCount = 0 var totalCount = 0 for x in 0 ..< height { for y in 0 ..< width { let point = CGPoint(x: x, y: y) let pixelInfo: Int = (width * Int(point.y)) + Int(point.x) * 4 let red = CGFloat(buffer[pixelInfo]) let green = CGFloat(buffer[pixelInfo + 1]) let blue = CGFloat(buffer[pixelInfo + 2]) if red == 255.0 && green == 255.0 && blue == 255.0 { whiteCount += 1 } totalCount += 1 } } let proportion: CGFloat = CGFloat(whiteCount / totalCount) if proportion > 0.95 { return true } else { return false } } private func scaleImage(image: UIImage) -> UIImage { let scale = 0.2 let newSize = CGSize(width: floor(image.size.width * scale), height: floor(image.size.height * scale)) if #available(iOS 13.0, *) { let renderer = UIGraphicsImageRenderer(size: newSize) renderer.image { rendererContext in return image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) } } return image } }
|