diff --git a/packages/url_launcher/url_launcher_ios/CHANGELOG.md b/packages/url_launcher/url_launcher_ios/CHANGELOG.md index a7a283075d4..5103c4e2ec1 100644 --- a/packages/url_launcher/url_launcher_ios/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_ios/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 6.3.3 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. +* Ensures the completion callback is invoked if the user dismisses the Safari view before the initial URL load completes. ## 6.3.2 diff --git a/packages/url_launcher/url_launcher_ios/example/ios/RunnerTests/URLLauncherTests.swift b/packages/url_launcher/url_launcher_ios/example/ios/RunnerTests/URLLauncherTests.swift index 966a3d63e6d..3b994ad49f6 100644 --- a/packages/url_launcher/url_launcher_ios/example/ios/RunnerTests/URLLauncherTests.swift +++ b/packages/url_launcher/url_launcher_ios/example/ios/RunnerTests/URLLauncherTests.swift @@ -131,6 +131,24 @@ final class URLLauncherTests: XCTestCase { XCTAssertEqual(launcher.passedOptions?[.universalLinksOnly] as? Bool, true) } + func testLaunchSafariViewControllerWithClose() { + let launcher = FakeLauncher() + let plugin = createPlugin(launcher: launcher) + + let expectation = XCTestExpectation(description: "completion called") + plugin.openUrlInSafariViewController(url: "https://flutter.dev") { result in + switch result { + case .success(let details): + XCTAssertEqual(details, .dismissed) + case .failure(let error): + XCTFail("Unexpected error: \(error)") + } + expectation.fulfill() + } + plugin.closeSafariViewController() + wait(for: [expectation], timeout: 30) + } + } final private class FakeLauncher: NSObject, Launcher { diff --git a/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/URLLaunchSession.swift b/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/URLLaunchSession.swift index b0761e57f08..7457eddf625 100644 --- a/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/URLLaunchSession.swift +++ b/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/URLLaunchSession.swift @@ -12,6 +12,7 @@ final class URLLaunchSession: NSObject, SFSafariViewControllerDelegate { private let completion: OpenInSafariCompletionHandler private let url: URL + private var isLoadCompleted: Bool = false /// The Safari view controller used for displaying the URL. let safariViewController: SFSafariViewController @@ -46,12 +47,16 @@ final class URLLaunchSession: NSObject, SFSafariViewControllerDelegate { } else { completion(.success(.failedToLoad)) } + isLoadCompleted = true } /// Called when the user finishes using the Safari view controller. /// /// - Parameter controller: The Safari view controller. func safariViewControllerDidFinish(_ controller: SFSafariViewController) { + if !isLoadCompleted { + completion(.success(.dismissed)) + } controller.dismiss(animated: true, completion: nil) didFinish?() } diff --git a/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/messages.g.swift b/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/messages.g.swift index 4c9c4693e89..85e1e3944c2 100644 --- a/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/messages.g.swift +++ b/packages/url_launcher/url_launcher_ios/ios/url_launcher_ios/Sources/url_launcher_ios/messages.g.swift @@ -85,6 +85,8 @@ enum InAppLoadResult: Int { case failedToLoad = 1 /// The URL could not be launched because it is invalid. case invalidUrl = 2 + /// The controller was closed before loading. + case dismissed = 3 } private class messagesPigeonCodecReader: FlutterStandardReader { diff --git a/packages/url_launcher/url_launcher_ios/lib/src/messages.g.dart b/packages/url_launcher/url_launcher_ios/lib/src/messages.g.dart index b4963035976..8aeea1a66a1 100644 --- a/packages/url_launcher/url_launcher_ios/lib/src/messages.g.dart +++ b/packages/url_launcher/url_launcher_ios/lib/src/messages.g.dart @@ -40,6 +40,9 @@ enum InAppLoadResult { /// The URL could not be launched because it is invalid. invalidUrl, + + /// The controller was closed before loading. + dismissed, } class _PigeonCodec extends StandardMessageCodec { diff --git a/packages/url_launcher/url_launcher_ios/lib/url_launcher_ios.dart b/packages/url_launcher/url_launcher_ios/lib/url_launcher_ios.dart index bb289abc569..27f48681d85 100644 --- a/packages/url_launcher/url_launcher_ios/lib/url_launcher_ios.dart +++ b/packages/url_launcher/url_launcher_ios/lib/url_launcher_ios.dart @@ -141,6 +141,8 @@ class UrlLauncherIOS extends UrlLauncherPlatform { throw _failedSafariViewControllerLoadException(url); case InAppLoadResult.invalidUrl: throw _invalidUrlException(); + case InAppLoadResult.dismissed: + return false; } } diff --git a/packages/url_launcher/url_launcher_ios/pigeons/messages.dart b/packages/url_launcher/url_launcher_ios/pigeons/messages.dart index c7097b41a74..998970c0ca5 100644 --- a/packages/url_launcher/url_launcher_ios/pigeons/messages.dart +++ b/packages/url_launcher/url_launcher_ios/pigeons/messages.dart @@ -32,6 +32,9 @@ enum InAppLoadResult { /// The URL could not be launched because it is invalid. invalidUrl, + + /// The controller was closed before loading. + dismissed, } @HostApi() diff --git a/packages/url_launcher/url_launcher_ios/pubspec.yaml b/packages/url_launcher/url_launcher_ios/pubspec.yaml index 4d11751a4a9..f6fa82f5dc7 100644 --- a/packages/url_launcher/url_launcher_ios/pubspec.yaml +++ b/packages/url_launcher/url_launcher_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher_ios description: iOS implementation of the url_launcher plugin. repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 -version: 6.3.2 +version: 6.3.3 environment: sdk: ^3.4.0