Skip to content
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

Delegate callback when web view process terminates #56

Merged
merged 1 commit into from
Jan 24, 2022

Conversation

joemasilotti
Copy link
Member

This is an intermediary solution for #50.

In summary, WKWebView can terminate under certain circumstances when in the background. When a Turbo-powered app is re-opened after this occurs the app can be left in a weird state.

This PR adds a new delegate callback, sessionWebViewProcessDidTerminate(_:), that developers can hook into to do what they see fit. @tony42, for example, is resetting the state of their app. I'm following that same approach.


I'm not sure if/how this can be handled better inside of this library short of iOS 16 fixing the issue entirely. So this feels like the next best approach as it puts the power back in the developer's hands.

@tony42
Copy link

tony42 commented Nov 30, 2021

@joemasilotti thanks for implementing the hook.

@ghiculescu
Copy link
Contributor

@joemasilotti @tony42 do either of you have any tips on how to fix this without this PR being merged? I'm not a Swift expert, is there an equivalent to Ruby monkey patching to implement the fix right away?

@joemasilotti
Copy link
Member Author

Not that I'm aware of, no. You could try to become the web view delegate, but that might mess things up with how the framework listens for events.

@jayohms will need to merge this in to enable the hook.

@chriskroon
Copy link

Hey, when I try to use this commit to my package, I get a build error:
Type 'SceneDelegate' does not conform to protocol 'SessionDelegate'

Am I doing something wrong?
Screenshot 2022-01-17 at 12 55 41

Cheers,
Chris

@joemasilotti
Copy link
Member Author

@chriskroon, nope! You need to implement the new method in SceneDelegate.

extension SceneDelegate: SessionDelegate { // If you already have this defined then only add the implementation below.
    func sessionWebViewProcessDidTerminate(_ session: Session) {
        // ...
    }
}

@chriskroon
Copy link

Hey Joe,

I found that out by myself and I thought that I replied haha.
Thx Joe!

Cheers,
Chris

@jayohms jayohms merged commit 30fdf97 into hotwired:main Jan 24, 2022
@jayohms
Copy link
Collaborator

jayohms commented Jan 24, 2022

Thanks for exposing this hook and sorry for the delay!

@dginsburg
Copy link

Thanks for diagnosing and fixing this @joemasilotti. I'd been tearing my hair out trying to figure out why the first visit was failing after the app had been in the background for a long time. I had assumed the app was terminated and the failure was part of a turbo cold boot.

ghiculescu added a commit to ghiculescu/turbo-ios that referenced this pull request Feb 16, 2022
The demo wasn't compiling after hotwired#56, this fixes it.

@joemasilotti if you have any tips for what to put in this function, it'd make for a better demo 👍
ghiculescu added a commit to ghiculescu/turbo-ios that referenced this pull request Mar 27, 2022
hotwired#50 is a common issue on iOS 15. It looks like every app should implement hotwired#56

To encourage that, this adds a simple implementation of the function to the quick start.

See also hotwired#69
@ghiculescu
Copy link
Contributor

For those watching this issue, has anyone implemented anything apart from this callback?

https://nevermeant.dev/handling-blank-wkwebviews/ and Telerik-Verified-Plugins/WKWebView#248 (comment) discuss timer-based approaches and I am curious if anyone has used them in a Turbo context with success. (Or if they haven't needed to because just implementing this callback and calling session.reload() did the job.)

@joemasilotti
Copy link
Member Author

In the Turbo Native apps I build and maintain I reset the entire app in the callback. For example, usually something like this.

func sessionWebViewProcessDidTerminate(_ session: Session) {
    navigationController.popViewController(animated: false)
    navigationController.viewControllers = []

    self.session = createSession()
    modalSession = createSession()

    startApp()
}

@joemasilotti joemasilotti deleted the webiew-did-terminate branch March 27, 2022 20:54
@ghiculescu
Copy link
Contributor

ghiculescu commented Mar 27, 2022

Nice, I might try the same. Have you found a reliable way to replicate the issue so you can test it?

@joemasilotti
Copy link
Member Author

Usually by opening our app then opening a bunch of other apps and switching back to ours. Playing a graphically intense game for a few seconds usually triggers it.

@joemasilotti
Copy link
Member Author

Following up for anyone who lands here in the future.

My comment above doesn't seem to work 100% of the time. Instead, I've opted for restarting the entire app as if it was launched cold. It's a worse experience for the user, but it works 100% of the time which is a better trade-off for me.

@chriskroon
Copy link

chriskroon commented Jun 17, 2022

Hey Joe,

I also implemented it that way, this hook you can use for whenever a scene will become active again

 func sceneWillEnterForeground(_ scene: UIScene) {
       // Your Code 
       (I open a link whenever it's set by a push notification of the last link)
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants