-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
[url_launcher] When not fully loaded, clicking close causes the callback to not be triggered correctly. #8582
base: main
Are you sure you want to change the base?
Conversation
…allback to not be triggered correctly.
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
This comment was marked as resolved.
This comment was marked as resolved.
This should be testable with native unit tests that directly drive calls to the |
@@ -12,6 +12,7 @@ final class URLLaunchSession: NSObject, SFSafariViewControllerDelegate { | |||
|
|||
private let completion: OpenInSafariCompletionHandler | |||
private let url: URL | |||
private var isLoadCompleted: Bool? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nullable boolean should only be used when there are three conceptually different states. The code in this PR only actually recognizes two.
This comment was marked as resolved.
This comment was marked as resolved.
That's a Dart unit test, which does not run the code you changed; native unit tests are here, as described in our contributor docs. |
(Marking as Draft pending the test, so it doesn't show up in review queues.) |
Oh, my God. I forgot. Thanks for the reminder. I’ve added the test. If you have time, you can continue review |
|
||
* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. | ||
* Fixes When not fully loaded, clicking close causes the callback to not be triggered correctly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of this?
* Fixes When not fully loaded, clicking close causes the callback to not be triggered correctly. | |
* Ensures the completion callback is invoked if the user dismisses the Safari view before the initial URL load completes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been adjusted.
} | ||
|
||
/// Called when the user finishes using the Safari view controller. | ||
/// | ||
/// - Parameter controller: The Safari view controller. | ||
func safariViewControllerDidFinish(_ controller: SFSafariViewController) { | ||
if !isLoadCompleted { | ||
completion(.success(.failedToLoad)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is .failedToLoad
the correct result here? Or we should add a new InAppLoadResult.dismissed
result?
If this is the correct result, should we update this comment to indicate this case can happen if the user dismisses the Safari view before the initial load completes?
packages/packages/url_launcher/url_launcher_ios/pigeons/messages.dart
Lines 30 to 31 in fd53793
/// The URL did not load successfully. | |
failedToLoad, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first, I did consider adding a new InAppLoadResult to describe the close action, but it seems it could lead to confusion among developers. This is because, currently, after a successful load, clicking the close button does not trigger any callback.
Additionally, when the user clicks close before the loading is complete, triggering the failedToLoad callback seems reasonable in a broader sense, as the interruption of the loading process can be considered a loading failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the correct result, should we update this comment to indicate this case can happen if the user dismisses the Safari view before the initial load completes?
Do you think it’s possible to modify the comment like this:
// The URL did not load successfully (or close the SFSafariViewController earlier)
expectation.fulfill() | ||
} | ||
plugin.closeSafariViewController() | ||
wait(for: [expectation], timeout: 30) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this timeout: 30
necessary or is timeout: 1
sufficient?
From my understanding plugin.closeSafariViewController()
calls the completion callback, which in turn calls expectation.fulfill()
. The expectation should be already be fulfilled at this point.
I apologize if this is a silly question, I'm not very familiar with XCTest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our standard for expectation timeouts in the repo is 30 (older code still uses lower timeouts). Flutter style is not to have timeouts at all but that's awkward with XCTest APIs, so we just use a value that is absurdly long for unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under normal circumstances, wait(for: [expectation], timeout: 30) won’t actually wait, because the closure has already been triggered before it. The 30-second timeout is set to prevent accidentally removing this PR functionality. If this PR functionality is deleted, setting the wait time to 1 might not make sense, as the callback may never be reached for verification.
let plugin = createPlugin(launcher: launcher) | ||
|
||
let expectation = XCTestExpectation(description: "completion called") | ||
plugin.openUrlInSafariViewController(url: "https://flutter.dev") { result in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry that this test would flake if https://flutter.dev
loads before the test calls closeSafariViewController
. Is there some URL we could test that is known to hang forever? Or am I overthinking this? cc @stuartmorgan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not expect it to be possible for that to happen. Unless SFSafariViewController
's didCompleteInitialLoad
callback happens on a non-main thread (which I wouldn't expect since it passes the view controller as a parameter), it shouldn't be possible for the callback to trigger until the runloop runs again, which I would think could not happen before the wait
call.
There are some assumptions in there, so I wouldn't be confident in saying that it's impossible, but I'd be fine with waiting to see if it does actually happen before we add a bunch of extra logic (since the reliable way to avoid that would be dependency injection of a fake SFSafariViewController
that we know won't load anything) to avoid I case that I strongly suspect is in fact impossible.
When SFSafariViewController is loading a webpage, if the close button is clicked during the loading process, it can prevent the callback from being triggered correctly.
List which issues are fixed by this PR. You must list at least one issue.
Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the [pub versioning philosophy], or this PR is [exempt from version changes].CHANGELOG.md
to add a description of the change, [following repository CHANGELOG style], or this PR is [exempt from CHANGELOG changes].///
).