用WKWebView加載3d模型發(fā)現(xiàn)在6P(6P畫質(zhì)好偶惠,3x煤蹭,屏幕大昼汗,但是內(nèi)存1G)上會白屏肴熏。但是別的機型沒有發(fā)現(xiàn)異常,白屏的主要原因是由于內(nèi)存占用太大顷窒。
WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件蛙吏,用以替代 UIKit 中笨重難用源哩、內(nèi)存泄漏的 UIWebView。WKWebView 擁有60fps滾動刷新率鸦做、和 safari 相同的 JavaScript 引擎等優(yōu)勢励烦。所以我覺得它很厲害,于是加載模型的任務(wù)當(dāng)然是它了泼诱,不再使用UIWebView坛掠。但是就出現(xiàn)了問題。
1.WKWebView 白屏問題
WKWebView 自詡擁有更快的加載速度治筒,更低的內(nèi)存占用屉栓,但實際上 WKWebView 是一個多進(jìn)程組件,Network Loading 以及 UI Rendering 在其它進(jìn)程中執(zhí)行耸袜。初次適配 WKWebView 的時候友多,我們也驚訝于打開 WKWebView 后,App 進(jìn)程內(nèi)存消耗反而大幅下降堤框,但是仔細(xì)觀察會發(fā)現(xiàn)域滥,Other Process 的內(nèi)存占用會增加。在一些用 webGL 渲染的復(fù)雜頁面蜈抓,使用 WKWebView 總體的內(nèi)存占用(App Process Memory + Other Process Memory)不見得比 UIWebView 少很多启绰。
在 UIWebView 上當(dāng)內(nèi)存占用太大的時候,App Process 會 crash资昧;而在 WKWebView 上當(dāng)總體的內(nèi)存占用比較大的時候酬土,WebContent Process 會 crash,從而出現(xiàn)白屏現(xiàn)象格带。在 WKWebView 中加載下面的測試鏈接可以穩(wěn)定重現(xiàn)白屏現(xiàn)象:
http://people.mozilla.org/~rnewman/fennec/mem.html
這個時候 WKWebView.URL 會變?yōu)?nil, 簡單的 reload 刷新操作已經(jīng)失效撤缴,對于一些長駐的H5頁面影響比較大。
A叽唱、借助 WKNavigtionDelegate
iOS 9以后 WKNavigtionDelegate 新增了一個回調(diào)函數(shù):
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
當(dāng) WKWebView 總體內(nèi)存占用過大屈呕,頁面即將白屏的時候,系統(tǒng)會調(diào)用上面的回調(diào)函數(shù)棺亭,我們在該函數(shù)里執(zhí)行[webView reload](這個時候 webView.URL 取值尚不為 nil)解決白屏問題虎眨。在一些高內(nèi)存消耗的頁面可能會頻繁刷新當(dāng)前頁面,H5側(cè)也要做相應(yīng)的適配操作镶摘。
B嗽桩、檢測 webView.title 是否為空
并不是所有H5頁面白屏的時候都會調(diào)用上面的回調(diào)函數(shù),比如凄敢,最近遇到在一個高內(nèi)存消耗的H5頁面上 present 系統(tǒng)相機碌冶,拍照完畢后返回原來頁面的時候出現(xiàn)白屏現(xiàn)象(拍照過程消耗了大量內(nèi)存,導(dǎo)致內(nèi)存緊張涝缝,WebContent Process 被系統(tǒng)掛起)扑庞,但上面的回調(diào)函數(shù)并沒有被調(diào)用譬重。在WKWebView白屏的時候,另一種現(xiàn)象是 webView.titile 會被置空, 因此罐氨,可以在 viewWillAppear 的時候檢測 webView.title 是否為空來 reload 頁面臀规。
綜合以上兩種方法可以解決絕大多數(shù)的白屏問題。
2. 但是reload后重新加載栅隐,還是會出現(xiàn)白屏塔嬉。真是醉了。后來還得回到UIWebView上约啊,用UIWebView加載就沒事邑遏。驗證了這句話。
初次適配 WKWebView 的時候恰矩,我們也驚訝于打開 WKWebView 后记盒,App 進(jìn)程內(nèi)存消耗反而大幅下降,但是仔細(xì)觀察會發(fā)現(xiàn)外傅,Other Process 的內(nèi)存占用會增加纪吮。在一些用 webGL 渲染的復(fù)雜頁面,使用 WKWebView 總體的內(nèi)存占用(App Process Memory + Other Process Memory)不見得比 UIWebView 少很多萎胰。我們加載的正是模型啊碾盟,用的 webGL渲染,所以WKWebView還沒UIWebView好呢技竟。所以選擇它們的時候還得考慮下公司的需求嘍冰肴。
UIWebView沒有實時的進(jìn)度提示,所以我做了個假的模仿WKWebView榔组∥跷荆看著還行能用。
#import "BaseViewController.h"
@interface BaseUIWebViewController : BaseViewController
- (instancetype)initWithUrl:(NSString *)urlStr;
@property(nonatomic,strong)UIWebView *webView;
@property(nonatomic,copy)NSString *urlString;
@property(nonatomic,strong)UIProgressView *progressView;
@end
//
// BaseUIWebViewController.m
//
// Created by wyb on 2017/4/7.
// Copyright ? 2017年 xxx. All rights reserved.
//
#import "BaseUIWebViewController.h"
@interface BaseUIWebViewController ()<UIWebViewDelegate>
@property(nonatomic,strong)NSTimer *timer;
@end
@implementation BaseUIWebViewController
- (instancetype)initWithUrl:(NSString *)urlStr{
self = [super init];
if (self) {
self.urlString = urlStr;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight-64)];
self.webView.delegate = self;
self.webView.opaque = NO;
self.webView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.webView];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(progressChange) userInfo:nil repeats:YES];
[self.timer setFireDate:[NSDate distantFuture]];
self.progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 0, KScreenWidth, 2)];
//進(jìn)度條的顏色
self.progressView.trackTintColor = [UIColor blackColor];
self.progressView.progressTintColor = KColorFromRGB(0x00c853);
[self.view addSubview:self.progressView];
if (self.urlString != nil) {
NSURL *url = [NSURL URLWithString:self.urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
}
- (void)dealloc
{
[self.timer invalidate];
self.timer = nil;
}
- (void)progressChange
{
self.progressView.progress += 0.002;
if (self.progressView.progress >0.8) {
self.progressView.progress += 0.0001;
}
if (self.progressView.progress >=1.0) {
[UIView animateWithDuration:0.25f animations:^{
self.progressView.alpha = 0.0f;
self.progressView.progress = 0.0f;
}];
}
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
[self.timer setFireDate:[NSDate date]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self finishedLoad];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[self finishedLoad];
}
- (void)finishedLoad
{
[self.timer invalidate];
self.timer = nil;
self.progressView.progress = 1.0;
[UIView animateWithDuration:0.25f animations:^{
self.progressView.alpha = 0.0f;
self.progressView.progress = 0.0f;
}];
}
@end