Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 0870628

Browse files
authored
Implement Link for native platforms (#3177)
1 parent 30ee306 commit 0870628

File tree

5 files changed

+418
-3
lines changed

5 files changed

+418
-3
lines changed

packages/url_launcher/url_launcher/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 5.7.7
2+
3+
* Introduce the Link widget with an implementation for native platforms.
4+
15
## 5.7.6
26

37
* Suppress deprecation warning on the `shouldOverrideUrlLoading` method on Android of the `FlutterWebChromeClient` class.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright 2017 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
export 'src/link.dart' show Link;
6+
export 'package:url_launcher_platform_interface/link.dart'
7+
show FollowLink, LinkTarget, LinkWidgetBuilder;
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright 2017 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:flutter/widgets.dart';
8+
import 'package:url_launcher/url_launcher.dart';
9+
import 'package:url_launcher_platform_interface/link.dart';
10+
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
11+
12+
/// A widget that renders a real link on the web, and uses WebViews in native
13+
/// platforms to open links.
14+
///
15+
/// Example link to an external URL:
16+
///
17+
/// ```dart
18+
/// Link(
19+
/// uri: Uri.parse('https://flutter.dev'),
20+
/// builder: (BuildContext context, FollowLink followLink) => RaisedButton(
21+
/// onPressed: followLink,
22+
/// // ... other properties here ...
23+
/// )},
24+
/// );
25+
/// ```
26+
///
27+
/// Example link to a route name within the app:
28+
///
29+
/// ```dart
30+
/// Link(
31+
/// uri: Uri.parse('/home'),
32+
/// builder: (BuildContext context, FollowLink followLink) => RaisedButton(
33+
/// onPressed: followLink,
34+
/// // ... other properties here ...
35+
/// )},
36+
/// );
37+
/// ```
38+
class Link extends StatelessWidget implements LinkInfo {
39+
/// Called at build time to construct the widget tree under the link.
40+
final LinkWidgetBuilder builder;
41+
42+
/// The destination that this link leads to.
43+
final Uri uri;
44+
45+
/// The target indicating where to open the link.
46+
final LinkTarget target;
47+
48+
/// Whether the link is disabled or not.
49+
bool get isDisabled => uri == null;
50+
51+
/// Creates a widget that renders a real link on the web, and uses WebViews in
52+
/// native platforms to open links.
53+
Link({
54+
Key key,
55+
@required this.uri,
56+
LinkTarget target,
57+
@required this.builder,
58+
}) : target = target ?? LinkTarget.defaultTarget,
59+
super(key: key);
60+
61+
LinkDelegate get _effectiveDelegate {
62+
return UrlLauncherPlatform.instance.linkDelegate ??
63+
DefaultLinkDelegate.create;
64+
}
65+
66+
@override
67+
Widget build(BuildContext context) {
68+
return _effectiveDelegate(this);
69+
}
70+
}
71+
72+
/// The default delegate used on non-web platforms.
73+
///
74+
/// For external URIs, it uses url_launche APIs. For app route names, it uses
75+
/// event channel messages to instruct the framework to push the route name.
76+
class DefaultLinkDelegate extends StatelessWidget {
77+
/// Creates a delegate for the given [link].
78+
const DefaultLinkDelegate(this.link);
79+
80+
/// Given a [link], creates an instance of [DefaultLinkDelegate].
81+
///
82+
/// This is a static method so it can be used as a tear-off.
83+
static DefaultLinkDelegate create(LinkInfo link) {
84+
return DefaultLinkDelegate(link);
85+
}
86+
87+
/// Information about the link built by the app.
88+
final LinkInfo link;
89+
90+
bool get _useWebView {
91+
if (link.target == LinkTarget.self) return true;
92+
if (link.target == LinkTarget.blank) return false;
93+
return null;
94+
}
95+
96+
Future<void> _followLink(BuildContext context) async {
97+
if (!link.uri.hasScheme) {
98+
// A uri that doesn't have a scheme is an internal route name. In this
99+
// case, we push it via Flutter's navigation system instead of letting the
100+
// browser handle it.
101+
final String routeName = link.uri.toString();
102+
return pushRouteNameToFramework(context, routeName);
103+
}
104+
105+
// At this point, we know that the link is external. So we use the `launch`
106+
// API to open the link.
107+
final String urlString = link.uri.toString();
108+
if (await canLaunch(urlString)) {
109+
await launch(
110+
urlString,
111+
forceSafariVC: _useWebView,
112+
forceWebView: _useWebView,
113+
);
114+
} else {
115+
FlutterError.reportError(FlutterErrorDetails(
116+
exception: 'Could not launch link $urlString',
117+
stack: StackTrace.current,
118+
library: 'url_launcher',
119+
context: ErrorDescription('during launching a link'),
120+
));
121+
}
122+
return Future<void>.value(null);
123+
}
124+
125+
@override
126+
Widget build(BuildContext context) {
127+
return link.builder(
128+
context,
129+
link.isDisabled ? null : () => _followLink(context),
130+
);
131+
}
132+
}

packages/url_launcher/url_launcher/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: url_launcher
22
description: Flutter plugin for launching a URL on Android and iOS. Supports
33
web, phone, SMS, and email schemes.
44
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher
5-
version: 5.7.6
5+
version: 5.7.7
66

77
flutter:
88
plugin:
@@ -24,13 +24,13 @@ flutter:
2424
dependencies:
2525
flutter:
2626
sdk: flutter
27-
url_launcher_platform_interface: ^1.0.8
27+
url_launcher_platform_interface: ^1.0.9
2828
# The design on https://flutter.dev/go/federated-plugins was to leave
2929
# this constraint as "any". We cannot do it right now as it fails pub publish
3030
# validation, so we set a ^ constraint.
3131
# TODO(amirh): Revisit this (either update this part in the design or the pub tool).
3232
# https://github.com/flutter/flutter/issues/46264
33-
url_launcher_web: ^0.1.3
33+
url_launcher_web: ^0.1.5
3434
url_launcher_linux: ^0.0.1
3535
url_launcher_macos: ^0.0.1
3636
url_launcher_windows: ^0.0.1

0 commit comments

Comments
 (0)