Skip to content

Commit 4354f65

Browse files
authored
[url_launcher] launchUrl always returns true for valid schemes on the web. (#7229)
## Description Since `noopener` is used to open URLs, there is no way to determine if the browser has succesfully opened a given URL ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#noopener)). Therefore success is now assumed for supported schemes. Fixes flutter/flutter#139783. Implementation largely follows suggestions by @ditman written down in [a comment](flutter/flutter#139783 (comment)). The only exception is that `launchUrl` does not returns a hard-coded `true`, but a `canLaunch(url)`. That way `false` is returned for invalid schemes (e.g. `javascript:`, as is checked in [an integration test](https://github.com/Frank3K/flutter_packages/blob/0c29f9463acb09a5ad8f1ada9ff16e7b8221bf68/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart#L119-L122)). ## Testing ### Sample application The following application can be used to validate the fix. Note that the `print` is executed using the current version of url_launcher_web (2.3.1) and that it does not execute when the fix from this PR is used. `main.dart` ```dart import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; final Uri _url = Uri.parse('https://flutter.dev'); void main() => runApp( const MaterialApp( home: Material( child: Center( child: ElevatedButton( onPressed: _launchUrl, child: Text('Show Flutter homepage'), ), ), ), ), ); Future<void> _launchUrl() async { if (!await launchUrl(_url)) { // ignore: avoid_print print('Failed opening link.'); } } ```
1 parent acadb40 commit 4354f65

File tree

5 files changed

+35
-7
lines changed

5 files changed

+35
-7
lines changed

packages/url_launcher/url_launcher_web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.3.3
2+
3+
* Changes `launchUrl` so it always returns `true`, except for disallowed URL schemes.
4+
15
## 2.3.2
26

37
* Adds support for `web: ^1.0.0`.

packages/url_launcher/url_launcher_web/README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,14 @@ In such cases, you can use the `webOnlyWindowName` parameter, setting it to
3030
`_self`, to open the URL within the current tab. Another approach is to ensure
3131
that the `uri` is synchronously ready.
3232

33-
Read more: MDN > [Transient activation](https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation).
33+
Read more: MDN > [Transient activation](https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation).
34+
35+
### Method `launchUrl` always returns `true` for allowed schemes
36+
37+
The `launchUrl` method always returns `true` on the web platform for allowed
38+
schemes. This is because URLs are opened in a new window using the `noopener`
39+
window feature. When the `noopener` feature is used, the browser does not
40+
return any information that can be used to determine if the link was
41+
successfully opened.
42+
43+
Read more: MDN > [window.open](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#noopener).

packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,15 @@ void main() {
120120
(WidgetTester _) async {
121121
expect(plugin.launch('javascript:alert("1")'), completion(isFalse));
122122
});
123+
124+
testWidgets('launching a unknown sceheme returns true',
125+
(WidgetTester _) async {
126+
expect(
127+
plugin.launch(
128+
'foo:bar',
129+
),
130+
completion(isTrue));
131+
});
123132
});
124133

125134
group('openNewWindow', () {

packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,30 @@ class UrlLauncherPlugin extends UrlLauncherPlatform {
6666

6767
/// Opens the given [url] in the specified [webOnlyWindowName].
6868
///
69-
/// Returns the newly created window.
69+
/// Always returns `true`, except for disallowed schemes. Because `noopener`
70+
/// is used as a window feature, it can not be detected if the window was
71+
/// opened successfully.
72+
/// See https://html.spec.whatwg.org/multipage/nav-history-apis.html#window-open-steps.
7073
@visibleForTesting
71-
html.Window? openNewWindow(String url, {String? webOnlyWindowName}) {
74+
bool openNewWindow(String url, {String? webOnlyWindowName}) {
7275
final String? scheme = _getUrlScheme(url);
7376
// Actively disallow opening some schemes, like javascript.
7477
// See https://github.com/flutter/flutter/issues/136657
7578
if (_isDisallowedScheme(scheme)) {
7679
if (kDebugMode) {
7780
print('Disallowed URL with scheme: $scheme');
7881
}
79-
return null;
82+
return false;
8083
}
8184
// Some schemes need to be opened on the _top window context on Safari.
8285
// See https://github.com/flutter/flutter/issues/51461
8386
final String target = webOnlyWindowName ??
8487
((_isSafari && _isSafariTargetTopScheme(scheme)) ? '_top' : '');
8588

8689
// ignore: unsafe_html
87-
return _window.open(url, target, 'noopener,noreferrer');
90+
_window.open(url, target, 'noopener,noreferrer');
91+
92+
return true;
8893
}
8994

9095
@override
@@ -109,7 +114,7 @@ class UrlLauncherPlugin extends UrlLauncherPlatform {
109114
@override
110115
Future<bool> launchUrl(String url, LaunchOptions options) async {
111116
final String? windowName = options.webOnlyWindowName;
112-
return openNewWindow(url, webOnlyWindowName: windowName) != null;
117+
return openNewWindow(url, webOnlyWindowName: windowName);
113118
}
114119

115120
@override

packages/url_launcher/url_launcher_web/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: url_launcher_web
22
description: Web platform implementation of url_launcher
33
repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22
5-
version: 2.3.2
5+
version: 2.3.3
66

77
environment:
88
sdk: ^3.3.0

0 commit comments

Comments
 (0)