一、在平时项目开发中,经常会使用WKWebView
加载一个H5
链接,加载完成后,用户可能去玩其他的App
,或者是接听电话,再从后台回到App,有时候会发现WKWebView
加载的H5
变成白屏
了,这样展示给用户非常的不友好。
二、造成H5
白屏的原因:
- 网络加载获取数据造成
- 系统软件版本造成
-
JS
语言兼容造成 - 内存不足造成
-
WKWebView
的content process
进程被回收kill
等
三、解决方案:
- 网络不好情况数据加载失败:
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
在这个方案里面添加失败处理,可以提那家一个重新加载的按钮图片等。
- 对于
WKWebView
的content process
进程被回收的处理,我们可以抓取屏幕的像素点
,白色
的像素点占某个区域
的多少值视为白屏,下面直接上代码,白色
像素点数占webview
超过85%,视为白屏,WKWebView
在iOS11
之后提供截图方法:
- (void)takeSnapshotWithConfiguration:(nullable WKSnapshotConfiguration *)snapshotConfiguration completionHandler:(void (^)(UIImage * _Nullable snapshotImage, NSError * _Nullable error))completionHandler WK_SWIFT_ASYNC_NAME(takeSnapshot(configuration:)) API_AVAILABLE(ios(11.0));
-
利用这个进行处理白屏,代码如下:
//声明一个webview加载状态枚举
typedef NS_ENUM(NSUInteger,webviewLoadingStatus) {
WebViewNormalStatus = 0, //正常
WebViewErrorStatus, //白屏
WebViewPendStatus, //待决
};
-
判断是否白屏方法封装:
#pragma mark -- 判断是否白屏方法封装
- (void)judgeLoadingStatus:(WKWebView *)webview withBlock:(void (^)(webviewLoadingStatus status))completionBlock{
webviewLoadingStatus __block status = WebViewPendStatus;
if (@available(iOS 11.0, *)) {
if (webview && [webview isKindOfClass:[WKWebView class]]) {
CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height; //状态栏高度
CGFloat navigationHeight = webview.viewController.navigationController.navigationBar.frame.size.height; //导航栏高度
WKSnapshotConfiguration *shotConfiguration = [[WKSnapshotConfiguration alloc] init];
shotConfiguration.rect = CGRectMake(0, statusBarHeight + navigationHeight, webview.bounds.size.width, (webview.bounds.size.height - navigationHeight - statusBarHeight)); //仅截图检测导航栏以下部分内容
[webview takeSnapshotWithConfiguration:shotConfiguration completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) {
if (snapshotImage) {
CGImageRef imageRef = snapshotImage.CGImage;
UIImage * scaleImage = [self scaleImage:snapshotImage];
BOOL isWhiteScreen = [self searchEveryPixel:scaleImage];
if (isWhiteScreen) {
status = WebViewErrorStatus;
}else{
status = WebViewNormalStatus;
}
}
if (completionBlock) {
completionBlock(status);
}
}];
}
}
}
-
图片缩放
//缩放图片
- (UIImage *)scaleImage: (UIImage *)image {
CGFloat scale = 0.2;
CGSize newsize;
newsize.width = floor(image.size.width * scale);
newsize.height = floor(image.size.height * scale);
if (@available(iOS 10.0, *)) {
UIGraphicsImageRenderer * renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newsize];
return [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
[image drawInRect:CGRectMake(0, 0, newsize.width, newsize.height)];
}];
}else{
return image;
}
}
-
遍历像素点 白色像素占比大于95%认定为白屏
- (BOOL)searchEveryPixel:(UIImage *)image {
CGImageRef cgImage = [image CGImage];
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage); //每个像素点包含r g b a 四个字节
size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
CFDataRef data = CGDataProviderCopyData(dataProvider);
UInt8 * buffer = (UInt8*)CFDataGetBytePtr(data);
int whiteCount = 0;
int totalCount = 0;
for (int j = 0; j < height; j ++ ) {
for (int i = 0; i < width; i ++) {
UInt8 * pt = buffer + j * bytesPerRow + i * (bitsPerPixel / 8);
UInt8 red = * pt;
UInt8 green = *(pt + 1);
UInt8 blue = *(pt + 2);
// UInt8 alpha = *(pt + 3);
totalCount ++;
if (red == 255 && green == 255 && blue == 255) {
whiteCount ++;
}
}
}
float proportion = (float)whiteCount / totalCount ;
NSLog(@"当前像素点数:%d,白色像素点数:%d , 占比: %f",totalCount , whiteCount , proportion );
if (proportion > 0.85) {
return YES;
}else{
return NO;
}
}
-
在后台回到前台发送通知,执行下面方法进行调佣:
[self judgeLoadingStatus:self.webView withBlock:^(webviewLoadingStatus status) {
if (status == WebViewErrorStatus) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
JKAlertDialog *alertVB = [[JKAlertDialog alloc] initWithTitle:@"温馨提示" message:@"内存不足或占用过大,资源被回收,是否重新加载"];
[alertVB addButton:Button_OK withTitle:@"取消" handler:^(JKAlertDialogItem *item) {
}];
[alertVB addButton:Button_OK withTitle:@"重新加载" handler:^(JKAlertDialogItem *item) {
//重新加载webview
[self rest_requestLoad];
}];
[alertVB show];
});
}
}];