@@ -22,88 +22,90 @@ class MyApp extends StatelessWidget {
22
22
theme: ThemeData (
23
23
primarySwatch: Colors .blue,
24
24
),
25
- home: MyHomePage (title: 'URL Launcher' ),
25
+ home: const MyHomePage (title: 'URL Launcher' ),
26
26
);
27
27
}
28
28
}
29
29
30
30
class MyHomePage extends StatefulWidget {
31
- MyHomePage ({Key ? key, required this .title}) : super (key: key);
31
+ const MyHomePage ({Key ? key, required this .title}) : super (key: key);
32
32
final String title;
33
33
34
34
@override
35
35
_MyHomePageState createState () => _MyHomePageState ();
36
36
}
37
37
38
38
class _MyHomePageState extends State <MyHomePage > {
39
+ bool _hasCallSupport = false ;
39
40
Future <void >? _launched;
40
41
String _phone = '' ;
41
42
43
+ @override
44
+ void initState () {
45
+ super .initState ();
46
+ // Check for phone call support.
47
+ canLaunch ('tel:123' ).then ((bool result) {
48
+ setState (() {
49
+ _hasCallSupport = result;
50
+ });
51
+ });
52
+ }
53
+
42
54
Future <void > _launchInBrowser (String url) async {
43
- if (await canLaunch (url)) {
44
- await launch (
45
- url,
46
- forceSafariVC: false ,
47
- forceWebView: false ,
48
- headers: < String , String > {'my_header_key' : 'my_header_value' },
49
- );
50
- } else {
55
+ if (! await launch (
56
+ url,
57
+ forceSafariVC: false ,
58
+ forceWebView: false ,
59
+ headers: < String , String > {'my_header_key' : 'my_header_value' },
60
+ )) {
51
61
throw 'Could not launch $url ' ;
52
62
}
53
63
}
54
64
55
65
Future <void > _launchInWebViewOrVC (String url) async {
56
- if (await canLaunch (url)) {
57
- await launch (
58
- url,
59
- forceSafariVC: true ,
60
- forceWebView: true ,
61
- headers: < String , String > {'my_header_key' : 'my_header_value' },
62
- );
63
- } else {
66
+ if (! await launch (
67
+ url,
68
+ forceSafariVC: true ,
69
+ forceWebView: true ,
70
+ headers: < String , String > {'my_header_key' : 'my_header_value' },
71
+ )) {
64
72
throw 'Could not launch $url ' ;
65
73
}
66
74
}
67
75
68
76
Future <void > _launchInWebViewWithJavaScript (String url) async {
69
- if (await canLaunch (url)) {
70
- await launch (
71
- url,
72
- forceSafariVC: true ,
73
- forceWebView: true ,
74
- enableJavaScript: true ,
75
- );
76
- } else {
77
+ if (! await launch (
78
+ url,
79
+ forceSafariVC: true ,
80
+ forceWebView: true ,
81
+ enableJavaScript: true ,
82
+ )) {
77
83
throw 'Could not launch $url ' ;
78
84
}
79
85
}
80
86
81
87
Future <void > _launchInWebViewWithDomStorage (String url) async {
82
- if (await canLaunch (url)) {
83
- await launch (
84
- url,
85
- forceSafariVC: true ,
86
- forceWebView: true ,
87
- enableDomStorage: true ,
88
- );
89
- } else {
88
+ if (! await launch (
89
+ url,
90
+ forceSafariVC: true ,
91
+ forceWebView: true ,
92
+ enableDomStorage: true ,
93
+ )) {
90
94
throw 'Could not launch $url ' ;
91
95
}
92
96
}
93
97
94
98
Future <void > _launchUniversalLinkIos (String url) async {
95
- if (await canLaunch (url)) {
96
- final bool nativeAppLaunchSucceeded = await launch (
99
+ final bool nativeAppLaunchSucceeded = await launch (
100
+ url,
101
+ forceSafariVC: false ,
102
+ universalLinksOnly: true ,
103
+ );
104
+ if (! nativeAppLaunchSucceeded) {
105
+ await launch (
97
106
url,
98
- forceSafariVC: false ,
99
- universalLinksOnly: true ,
107
+ forceSafariVC: true ,
100
108
);
101
- if (! nativeAppLaunchSucceeded) {
102
- await launch (
103
- url,
104
- forceSafariVC: true ,
105
- );
106
- }
107
109
}
108
110
}
109
111
@@ -115,16 +117,22 @@ class _MyHomePageState extends State<MyHomePage> {
115
117
}
116
118
}
117
119
118
- Future <void > _makePhoneCall (String url) async {
119
- if (await canLaunch (url)) {
120
- await launch (url);
121
- } else {
122
- throw 'Could not launch $url ' ;
123
- }
120
+ Future <void > _makePhoneCall (String phoneNumber) async {
121
+ // Use `Uri` to ensure that `phoneNumber` is properly URL-encoded.
122
+ // Just using 'tel:$phoneNumber' would create invalid URLs in some cases,
123
+ // such as spaces in the input, which would cause `launch` to fail on some
124
+ // platforms.
125
+ final Uri launchUri = Uri (
126
+ scheme: 'tel' ,
127
+ path: phoneNumber,
128
+ );
129
+ await launch (launchUri.toString ());
124
130
}
125
131
126
132
@override
127
133
Widget build (BuildContext context) {
134
+ // onPressed calls using this URL are not gated on a 'canLaunch' check
135
+ // because the assumption is that every device can launch a web URL.
128
136
const String toLaunch = 'https://www.cylog.org/headers/' ;
129
137
return Scaffold (
130
138
appBar: AppBar (
@@ -143,10 +151,14 @@ class _MyHomePageState extends State<MyHomePage> {
143
151
hintText: 'Input the phone number to launch' )),
144
152
),
145
153
ElevatedButton (
146
- onPressed: () => setState (() {
147
- _launched = _makePhoneCall ('tel:$_phone ' );
148
- }),
149
- child: const Text ('Make phone call' ),
154
+ onPressed: _hasCallSupport
155
+ ? () => setState (() {
156
+ _launched = _makePhoneCall (_phone);
157
+ })
158
+ : null ,
159
+ child: _hasCallSupport
160
+ ? const Text ('Make phone call' )
161
+ : const Text ('Calling not supported' ),
150
162
),
151
163
const Padding (
152
164
padding: EdgeInsets .all (16.0 ),
@@ -201,11 +213,11 @@ class _MyHomePageState extends State<MyHomePage> {
201
213
uri: Uri .parse (
202
214
'https://pub.dev/documentation/url_launcher/latest/link/link-library.html' ),
203
215
target: LinkTarget .blank,
204
- builder: (ctx, openLink) {
216
+ builder: (BuildContext ctx, FollowLink ? openLink) {
205
217
return TextButton .icon (
206
218
onPressed: openLink,
207
- label: Text ('Link Widget documentation' ),
208
- icon: Icon (Icons .read_more),
219
+ label: const Text ('Link Widget documentation' ),
220
+ icon: const Icon (Icons .read_more),
209
221
);
210
222
},
211
223
),
0 commit comments