Skip to content

White Screen of Death issue | Enhance WebView reload detection to handle empty title strings #1552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ @interface CDVWebViewEngine ()
@property (nonatomic, readwrite) NSString *CDV_ASSETS_URL;
@property (nonatomic, readwrite) Boolean cdvIsFileScheme;
@property (nullable, nonatomic, strong, readwrite) WKWebViewConfiguration *configuration;
@property (nonatomic, strong) NSURL* lastGoodURL;

@end

Expand Down Expand Up @@ -271,6 +272,8 @@ - (void)pluginInitialize
name:UIApplicationWillEnterForegroundNotification object:nil];

NSLog(@"Using WKWebView");

[self addURLObserver];
}

- (void)dispose
Expand All @@ -282,10 +285,41 @@ - (void)dispose
[super dispose];
}

- (void)onReset {
[self addURLObserver];
}

static void * KVOContext = &KVOContext;

- (void)addURLObserver {
if(!IsAtLeastiOSVersion(@"9.0")){
[self.webView addObserver:self forKeyPath:@"URL" options:0 context:KVOContext];
}
}

- (void) onAppWillEnterForeground:(NSNotification*)notification {
if ([self shouldReloadWebView]) {
NSLog(@"%@", @"CDVWebViewEngine reloading!");
[(WKWebView*)_engineWebView reload];

// PATCH FOR WHITE SCREEN OF DEATH:
// Try cached good URL first, then current URL, then fall back to app URL
WKWebView* wkWebView = (WKWebView*)_engineWebView;
NSURL* currentURL = wkWebView.URL;

NSURL* url;
if (self.lastGoodURL) {
url = self.lastGoodURL;
NSLog(@"CDVWebViewEngine using cached good URL for reload: %@", url.absoluteString);
} else if (currentURL && ![currentURL.absoluteString isEqualToString:@"about:blank"] && ![currentURL.absoluteString isEqualToString:@""]) {
url = currentURL;
NSLog(@"CDVWebViewEngine using current page URL for reload: %@", url.absoluteString);
} else {
url = [((CDVViewController*) self.viewController) appUrl];
NSLog(@"CDVWebViewEngine using fallback app URL for reload: %@", url.absoluteString);
}

NSURLRequest* appReq = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
[wkWebView loadRequest:appReq];
}
}

Expand All @@ -297,7 +331,7 @@ - (BOOL)shouldReloadWebView

- (BOOL)shouldReloadWebView:(NSURL*)location title:(NSString*)title
{
BOOL title_is_nil = (title == nil);
BOOL title_is_nil = (title == nil) || [title isEqualToString:@""];
BOOL location_is_blank = [[location absoluteString] isEqualToString:@"about:blank"];

BOOL reload = (title_is_nil || location_is_blank);
Expand Down Expand Up @@ -482,12 +516,25 @@ - (CDVWebViewPermissionGrantType)parsePermissionGrantType:(NSString*)optionStrin

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"themeColor"]) {
if (context == KVOContext) {
if (object == [self webView] && [keyPath isEqualToString: @"URL"]) {
NSURL* currentURL = [object valueForKeyPath:keyPath];
if (currentURL == nil) {
NSLog(@"URL is nil. Reloading WKWebView");
[(WKWebView*)_engineWebView reload];
} else if (![currentURL.absoluteString isEqualToString:@"about:blank"] && ![currentURL.absoluteString isEqualToString:@""]) {
// Cache good URLs via KVO as backup
self.lastGoodURL = currentURL;
}
}
} else if ([keyPath isEqualToString:@"themeColor"]) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
if (@available(iOS 15.0, *)) {
[self.viewController setStatusBarWebViewColor:((WKWebView *)self.engineWebView).themeColor];
}
#endif
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

Expand Down Expand Up @@ -536,6 +583,12 @@ - (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*

- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation
{
// Always cache successful URL loads (even if we're not the primary navigation delegate)
if (webView.URL && ![webView.URL.absoluteString isEqualToString:@"about:blank"] && ![webView.URL.absoluteString isEqualToString:@""]) {
self.lastGoodURL = webView.URL;
NSLog(@"CDVWebViewEngine cached good URL: %@", webView.URL.absoluteString);
}

[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:webView]];
}

Expand All @@ -562,7 +615,26 @@ - (void)webView:(WKWebView*)theWebView didFailNavigation:(WKNavigation*)navigati

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
{
[webView reload];
NSLog(@"CDVWebViewEngine: Web content process terminated, reloading with cached URL");

// PATCH FOR WHITE SCREEN OF DEATH:
// Use cached good URL first, then current URL, then fall back to app URL
NSURL* currentURL = webView.URL;

NSURL* url;
if (self.lastGoodURL) {
url = self.lastGoodURL;
NSLog(@"CDVWebViewEngine using cached good URL for process termination reload: %@", url.absoluteString);
} else if (currentURL && ![currentURL.absoluteString isEqualToString:@"about:blank"] && ![currentURL.absoluteString isEqualToString:@""]) {
url = currentURL;
NSLog(@"CDVWebViewEngine using current page URL for process termination reload: %@", url.absoluteString);
} else {
url = [((CDVViewController*) self.viewController) appUrl];
NSLog(@"CDVWebViewEngine using fallback app URL for process termination reload: %@", url.absoluteString);
}

NSURLRequest* appReq = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
[webView loadRequest:appReq];
}

- (BOOL)defaultResourcePolicyForURL:(NSURL*)url
Expand Down Expand Up @@ -684,4 +756,4 @@ - (void)userContentController:(WKUserContentController *)userContentController d
[self.scriptMessageHandler userContentController:userContentController didReceiveScriptMessage:message];
}

@end
@end