Skip to content

Commit 73d2f3e

Browse files
[url_launcher] Simplify Linux implementation (#5376)
The Linux implementation's method channel code was never simplified after the switch from a shared method channel to per-package method channels, so there was still cruft from the cross-platform channel API. This removes everything that's not used by the Linux native implementation, simplifying the protocol. This also adds direct support for `launchUrl`, so we're no longer relying on the redirection from the deprecated `launch`.
1 parent d9ee0bf commit 73d2f3e

File tree

6 files changed

+44
-122
lines changed

6 files changed

+44
-122
lines changed

packages/url_launcher/url_launcher_linux/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
## NEXT
1+
## 3.1.1
22

3+
* Implements `launchUrl`.
4+
* Simplifies method channel interface by removing unused elements.
35
* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
46

57
## 3.1.0

packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ class UrlLauncherLinux extends UrlLauncherPlatform {
2222
final LinkDelegate? linkDelegate = null;
2323

2424
@override
25-
Future<bool> canLaunch(String url) {
26-
return _channel.invokeMethod<bool>(
27-
'canLaunch',
28-
<String, Object>{'url': url},
29-
).then((bool? value) => value ?? false);
25+
Future<bool> canLaunch(String url) async {
26+
return (await _channel.invokeMethod<bool>('canLaunch', url)) ?? false;
3027
}
3128

3229
@override
@@ -40,16 +37,14 @@ class UrlLauncherLinux extends UrlLauncherPlatform {
4037
required Map<String, String> headers,
4138
String? webOnlyWindowName,
4239
}) {
43-
return _channel.invokeMethod<bool>(
44-
'launch',
45-
<String, Object>{
46-
'url': url,
47-
'enableJavaScript': enableJavaScript,
48-
'enableDomStorage': enableDomStorage,
49-
'universalLinksOnly': universalLinksOnly,
50-
'headers': headers,
51-
},
52-
).then((bool? value) => value ?? false);
40+
// None of the options are supported, so they don't need to be converted to
41+
// LaunchOptions.
42+
return launchUrl(url, const LaunchOptions());
43+
}
44+
45+
@override
46+
Future<bool> launchUrl(String url, LaunchOptions options) async {
47+
return (await _channel.invokeMethod<bool>('launch', url)) ?? false;
5348
}
5449

5550
@override

packages/url_launcher/url_launcher_linux/linux/test/url_launcher_linux_test.cc

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ namespace url_launcher_plugin {
1515
namespace test {
1616

1717
TEST(UrlLauncherPlugin, CanLaunchSuccess) {
18-
g_autoptr(FlValue) args = fl_value_new_map();
19-
fl_value_set_string_take(args, "url",
20-
fl_value_new_string("https://flutter.dev"));
18+
g_autoptr(FlValue) args = fl_value_new_string("https://flutter.dev");
2119
g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
2220
ASSERT_NE(response, nullptr);
2321
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
@@ -28,8 +26,7 @@ TEST(UrlLauncherPlugin, CanLaunchSuccess) {
2826
}
2927

3028
TEST(UrlLauncherPlugin, CanLaunchFailureUnhandled) {
31-
g_autoptr(FlValue) args = fl_value_new_map();
32-
fl_value_set_string_take(args, "url", fl_value_new_string("madeup:scheme"));
29+
g_autoptr(FlValue) args = fl_value_new_string("madeup:scheme");
3330
g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
3431
ASSERT_NE(response, nullptr);
3532
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
@@ -40,8 +37,7 @@ TEST(UrlLauncherPlugin, CanLaunchFailureUnhandled) {
4037
}
4138

4239
TEST(UrlLauncherPlugin, CanLaunchFileSuccess) {
43-
g_autoptr(FlValue) args = fl_value_new_map();
44-
fl_value_set_string_take(args, "url", fl_value_new_string("file:///"));
40+
g_autoptr(FlValue) args = fl_value_new_string("file:///");
4541
g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
4642
ASSERT_NE(response, nullptr);
4743
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
@@ -52,9 +48,8 @@ TEST(UrlLauncherPlugin, CanLaunchFileSuccess) {
5248
}
5349

5450
TEST(UrlLauncherPlugin, CanLaunchFailureInvalidFileExtension) {
55-
g_autoptr(FlValue) args = fl_value_new_map();
56-
fl_value_set_string_take(
57-
args, "url", fl_value_new_string("file:///madeup.madeupextension"));
51+
g_autoptr(FlValue) args =
52+
fl_value_new_string("file:///madeup.madeupextension");
5853
g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
5954
ASSERT_NE(response, nullptr);
6055
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
@@ -67,8 +62,7 @@ TEST(UrlLauncherPlugin, CanLaunchFailureInvalidFileExtension) {
6762
// For consistency with the established mobile implementations,
6863
// an invalid URL should return false, not an error.
6964
TEST(UrlLauncherPlugin, CanLaunchFailureInvalidUrl) {
70-
g_autoptr(FlValue) args = fl_value_new_map();
71-
fl_value_set_string_take(args, "url", fl_value_new_string(""));
65+
g_autoptr(FlValue) args = fl_value_new_string("");
7266
g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
7367
ASSERT_NE(response, nullptr);
7468
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));

packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313

1414
// See url_launcher_channel.dart for documentation.
1515
const char kChannelName[] = "plugins.flutter.io/url_launcher_linux";
16-
const char kBadArgumentsError[] = "Bad Arguments";
1716
const char kLaunchError[] = "Launch Error";
1817
const char kCanLaunchMethod[] = "canLaunch";
1918
const char kLaunchMethod[] = "launch";
20-
const char kUrlKey[] = "url";
2119

2220
struct _FlUrlLauncherPlugin {
2321
GObject parent_instance;
@@ -30,21 +28,6 @@ struct _FlUrlLauncherPlugin {
3028

3129
G_DEFINE_TYPE(FlUrlLauncherPlugin, fl_url_launcher_plugin, g_object_get_type())
3230

33-
// Gets the URL from the arguments or generates an error.
34-
static gchar* get_url(FlValue* args, GError** error) {
35-
if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) {
36-
g_set_error(error, 0, 0, "Argument map missing or malformed");
37-
return nullptr;
38-
}
39-
FlValue* url_value = fl_value_lookup_string(args, kUrlKey);
40-
if (url_value == nullptr) {
41-
g_set_error(error, 0, 0, "Missing URL");
42-
return nullptr;
43-
}
44-
45-
return g_strdup(fl_value_get_string(url_value));
46-
}
47-
4831
// Checks if URI has launchable file resource.
4932
static gboolean can_launch_uri_with_file_resource(FlUrlLauncherPlugin* self,
5033
const gchar* url) {
@@ -57,12 +40,7 @@ static gboolean can_launch_uri_with_file_resource(FlUrlLauncherPlugin* self,
5740

5841
// Called to check if a URL can be launched.
5942
FlMethodResponse* can_launch(FlUrlLauncherPlugin* self, FlValue* args) {
60-
g_autoptr(GError) error = nullptr;
61-
g_autofree gchar* url = get_url(args, &error);
62-
if (url == nullptr) {
63-
return FL_METHOD_RESPONSE(fl_method_error_response_new(
64-
kBadArgumentsError, error->message, nullptr));
65-
}
43+
const gchar* url = fl_value_get_string(args);
6644

6745
gboolean is_launchable = FALSE;
6846
g_autofree gchar* scheme = g_uri_parse_scheme(url);
@@ -82,14 +60,10 @@ FlMethodResponse* can_launch(FlUrlLauncherPlugin* self, FlValue* args) {
8260

8361
// Called when a URL should launch.
8462
static FlMethodResponse* launch(FlUrlLauncherPlugin* self, FlValue* args) {
85-
g_autoptr(GError) error = nullptr;
86-
g_autofree gchar* url = get_url(args, &error);
87-
if (url == nullptr) {
88-
return FL_METHOD_RESPONSE(fl_method_error_response_new(
89-
kBadArgumentsError, error->message, nullptr));
90-
}
63+
const gchar* url = fl_value_get_string(args);
9164

9265
FlView* view = fl_plugin_registrar_get_view(self->registrar);
66+
g_autoptr(GError) error = nullptr;
9367
gboolean launched;
9468
if (view != nullptr) {
9569
GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)));

packages/url_launcher/url_launcher_linux/pubspec.yaml

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

77
environment:
88
sdk: ">=3.0.0 <4.0.0"

packages/url_launcher/url_launcher_linux/test/url_launcher_linux_test.dart

Lines changed: 21 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,7 @@ void main() {
3838
await launcher.canLaunch('http://example.com/');
3939
expect(
4040
log,
41-
<Matcher>[
42-
isMethodCall('canLaunch', arguments: <String, Object>{
43-
'url': 'http://example.com/',
44-
})
45-
],
41+
<Matcher>[isMethodCall('canLaunch', arguments: 'http://example.com/')],
4642
);
4743
});
4844

@@ -66,65 +62,7 @@ void main() {
6662
);
6763
expect(
6864
log,
69-
<Matcher>[
70-
isMethodCall('launch', arguments: <String, Object>{
71-
'url': 'http://example.com/',
72-
'enableJavaScript': false,
73-
'enableDomStorage': false,
74-
'universalLinksOnly': false,
75-
'headers': <String, String>{},
76-
})
77-
],
78-
);
79-
});
80-
81-
test('launch with headers', () async {
82-
final UrlLauncherLinux launcher = UrlLauncherLinux();
83-
await launcher.launch(
84-
'http://example.com/',
85-
useSafariVC: true,
86-
useWebView: false,
87-
enableJavaScript: false,
88-
enableDomStorage: false,
89-
universalLinksOnly: false,
90-
headers: const <String, String>{'key': 'value'},
91-
);
92-
expect(
93-
log,
94-
<Matcher>[
95-
isMethodCall('launch', arguments: <String, Object>{
96-
'url': 'http://example.com/',
97-
'enableJavaScript': false,
98-
'enableDomStorage': false,
99-
'universalLinksOnly': false,
100-
'headers': <String, String>{'key': 'value'},
101-
})
102-
],
103-
);
104-
});
105-
106-
test('launch universal links only', () async {
107-
final UrlLauncherLinux launcher = UrlLauncherLinux();
108-
await launcher.launch(
109-
'http://example.com/',
110-
useSafariVC: false,
111-
useWebView: false,
112-
enableJavaScript: false,
113-
enableDomStorage: false,
114-
universalLinksOnly: true,
115-
headers: const <String, String>{},
116-
);
117-
expect(
118-
log,
119-
<Matcher>[
120-
isMethodCall('launch', arguments: <String, Object>{
121-
'url': 'http://example.com/',
122-
'enableJavaScript': false,
123-
'enableDomStorage': false,
124-
'universalLinksOnly': true,
125-
'headers': <String, String>{},
126-
})
127-
],
65+
<Matcher>[isMethodCall('launch', arguments: 'http://example.com/')],
12866
);
12967
});
13068

@@ -143,6 +81,25 @@ void main() {
14381
expect(launched, false);
14482
});
14583

84+
group('launchUrl', () {
85+
test('passes URL', () async {
86+
final UrlLauncherLinux launcher = UrlLauncherLinux();
87+
await launcher.launchUrl('http://example.com/', const LaunchOptions());
88+
expect(
89+
log,
90+
<Matcher>[isMethodCall('launch', arguments: 'http://example.com/')],
91+
);
92+
});
93+
94+
test('returns false if platform returns null', () async {
95+
final UrlLauncherLinux launcher = UrlLauncherLinux();
96+
final bool launched = await launcher.launchUrl(
97+
'http://example.com/', const LaunchOptions());
98+
99+
expect(launched, false);
100+
});
101+
});
102+
146103
group('supportsMode', () {
147104
test('returns true for platformDefault', () async {
148105
final UrlLauncherLinux launcher = UrlLauncherLinux();

0 commit comments

Comments
 (0)