pichillilorenzo / flutter_inappwebview

A Flutter plugin that allows you to add an inline webview, to use a headless webview, and to open an in-app browser window.
https://inappwebview.dev
Apache License 2.0
3.01k stars 1.33k forks source link

[iOS] shouldOverrideUrLoading issue with intercepting link to open a new window using url launcher #2089

Open gd46 opened 1 month ago

gd46 commented 1 month ago

Environment

Technology Version
Flutter version 3.13.8+
Plugin version 6.0.0
iOS version 17.x+
Xcode version 15.2
Url launcher 6.1.14

Issue was introduced on v6.0.0-beta.26 by this commit

https://github.com/pichillilorenzo/flutter_inappwebview/commit/e62348adc7efae3ce38dc6c84729ed17c0f361c2

Last worked on v6.0.0-beta.25

Device information: iPhone 15

public func webView(_ webView: WKWebView,
                 decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        var decisionHandlerCalled = false
        let callback = WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback()
        callback.nonNullSuccess = { (response: WKNavigationActionPolicy) in
            decisionHandlerCalled = true
            decisionHandler(response)
            return false
        }
        callback.defaultBehaviour = { (response: WKNavigationActionPolicy?) in
            if !decisionHandlerCalled {
                decisionHandlerCalled = true
                decisionHandler(.allow)
            }
        }
        callback.error = { [weak callback] (code: String, message: String?, details: Any?) in
            print(code + ", " + (message ?? ""))
            callback?.defaultBehaviour(nil)
        }

        let runCallback = {
            if let useShouldOverrideUrlLoading = self.settings?.useShouldOverrideUrlLoading, useShouldOverrideUrlLoading, let channelDelegate = self.channelDelegate {
                channelDelegate.shouldOverrideUrlLoading(navigationAction: navigationAction, callback: callback)
            } else {
                callback.defaultBehaviour(nil)
            }
        }

        if windowId != nil, !windowCreated {
            windowBeforeCreatedCallbacks.append(runCallback)
        } else {
            runCallback()
        }
    }

When shouldOverrideUrlLoading intercepts a link to launch using url launcher package the windowId here is not always null and then never executes the runCallback causing the link to not open. In testing introducing a delay around the following piece caused the issue to happen more frequently:

 if windowId != nil, !windowCreated {
    windowBeforeCreatedCallbacks.append(runCallback)
} else {
     runCallback()
 }

Expected behavior:

shouldOverrideUrlLoading should execute every time so that the url launcher can open the link

Current behavior:

runCallback is never executed(because windowId is not null, and windowBeforeCreatedCallbacks adds the runCallback but is not executed until webview is destroyed). so the link does not open. The windowId gets removed / reset when the webview is destroyed.

Steps to reproduce

  1. Create a webview utilizing the shouldOverrideUrlLoading
  2. Intercept links to launch a url
  3. Open and close that link rapidly. If this doesn't work, use a page with two links and alternate between them. 3.1. Another option is to update the runCallback check in a delay which increases the problem:
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
       if windowId != nil, !windowCreated {
            windowBeforeCreatedCallbacks.append(runCallback)
        } else {
            runCallback()
        }
    }
github-actions[bot] commented 1 month ago

👋 @gd46

NOTE: This comment is auto-generated.

Are you sure you have already searched for the same problem?

Some people open new issues but they didn't search for something similar or for the same issue. Please, search for it using the GitHub issue search box or on the official inappwebview.dev website, or, also, using Google, StackOverflow, etc. before posting a new one. You may already find an answer to your problem!

If this is really a new issue, then thank you for raising it. I will investigate it and get back to you as soon as possible. Please, make sure you have given me as much context as possible! Also, if you didn't already, post a code example that can replicate this issue.

In the meantime, you can already search for some possible solutions online! Because this plugin uses native WebView, you can search online for the same issue adding android WebView [MY ERROR HERE] or ios WKWebView [MY ERROR HERE] keywords.

Following these steps can save you, me, and other people a lot of time, thanks!