Search code examples
javascriptswiftwkwebview

WKWebView app unloads in background - reliable way to check


sometimes in background my WKWebView app unloads - when I open it I have only WKWebView background and the app doesn't respond. I managed to catch it once - I debugged it in safari dev tools and found out at that time it had 'about:blank' url loaded instead of my app url. So I did the following:

    @objc func applicationDidBecomeActive() {
        generateHapticFeedback(feedbackId: 4)
        
        let isAlive: Bool = webView.url?.absoluteString != URL(string:"about:blank")?.absoluteString
        
        if (isAlive) {
            print("[alive_check] OK, NO RELOAD NEEDED")
            return
        } else {
            print("[alive_check] HANGED")
            configurateWebView()
            HTMLLoader.loadScenario(for: webView)
            webView.evaluateJavaScript("alert('DEV MODE: APP HANG DETECTED. REINIT TO THE RESQUE 🦸🦸‍♀️🍔')")
        }
    }
    

I verified my approach works fine for scenario with 'about:blank' - to test it I just set window.location.href = 'about:blank' manually via safari dev tools. But it seems that app doesn't always have this state when unloads (this morning I have this again, and the fix doesn't help. at the same time I'm unable to connect to it with debugger after the night)

Do I have any reliable way to check that my page is still running in WKWebView and if no I will force it to reload?

I also tried to evaluate javascript to communicate to my page but it doesn't return anything.

Solutions I don't want to consider as of now:

  • Keep it live in background - reloading the page is completely fine to me as the app will restore it's state.

  • Reinitialize it every time on applicationDidBecomeActive as it looks a bit ugly in terms of UX.


Solution

  • Okay so I figured out the following - iOS unloads app into two different states:

    1. webView.url?.absoluteString == nil
    2. webView.url?.absoluteString == "about:blank"

    This states usually appear as white webView screen, mine has the color of the app though so it doesn't flash on loading)

    so what I did - on app activation I check that webView url contains my MY_URL_NAME_SEGMENT and url is not nil. This covers both cases I have when my app is unloaded. See the code below:

    
        @objc func applicationDidBecomeActive() {
            let currentUrl = webView.url?.absoluteString
            let isAlive = currentUrl != nil && currentUrl!.localizedLowercase.contains("MY_URL_NAME_SEGMENT".localizedLowercase)
    
            if (isAlive) {
                print("[alive_check] OK, NO RELOAD NEEDED")
                webView.evaluateJavaScript("alert('[✅ OK] isAlive: \(isAlive). URL: \(String(describing: webView.url?.absoluteString))')")
            } else {
                print("[alive_check] HANGED")
                webView.evaluateJavaScript("alert('[❌ RELOADED] isAlive: \(isAlive). URL: \(String(describing: webView.url?.absoluteString))')")
                configurateWebView()
                HTMLLoader.loadScenario(for: webView)//inside I just load html
            }
            
        }
    
    

    I also left example how I call javascript alert() so you will be able to debug the values anytime (you won't need to connect to debugger). Just make sure JS alerts works in your app in general - they must be implemented in your extension.