How to Launch URLs from Your App with Flutter’s URL_Launcher Package

Filip Doganowski
Tech Blog
Published in
5 min readMar 18, 2023

You should learn about the url_launcher package to add more functionality to your Flutter app. With this package, you can launch URLs, open email apps, dial phone numbers, and more from within your app. Utilizing this package can create a more seamless and user-friendly experience for your app’s users, making it an essential tool for any Flutter developer.

Photo by NASA on Unsplash

We will be coding an example in this article, and the source code will be available at the end. Let’s begin!

Install the package

To get started, install the url_launcher package from pub.dev.

You can add the dependency to your pubspec.yaml but I prefer to run the command bellow in my terminal:

flutter pub add url_launcher

IOS update info.plist

When launching an external app or service via a URL, the app needs to know which schemes to allow. By default, iOS only allows a limited number of schemes, such as HTTP, HTTPS, and mailto. To launch other schemes, such as sms and tel, they must be explicitly added to the LSApplicationQueriesSchemes array in the info.plist file.

Open and add the code bellow to the following file:ios/Runner/info.plist

<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
</array>

After adding the code above you need to restart the IOS simulator.

Android update AndroidManifest.xml

We need to modify the following file:
android/app/src/main/AndroidManifest.xml

For the url_launcher to work you need to add the code bellow at the top of the AndroidManifest.xml file just above <application>

    <!-- Provide required visibility configuration for API level 30 and above -->
<queries>
<!-- If your app opens https URLs -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<!-- If your app opens http URLs -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>

By default http urls are not supported so to enable the opening of them, we need to add android:usesCleartextTraffic=”true” at the top inside <application>, so in short change from:

<application
android:label="MyInvoices"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">

to:

<application
android:label="MyInvoices"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon"
android:usesCleartextTraffic="true">

After making these changes, restart the Android simulator as well.

Setting up…

Now we just need to make a few adjustments

Importing URL_Launcher

Now in your Dart code, you can use the following code to import the URL_Launcher package:

import 'package:url_launcher/url_launcher.dart';

Create a URL file

To keep the code architecture clean I create a separate file with URLs like bellow, this makes changing the URLs easier in the future.

String httpsLink = 'https://medium.com/@filip.doganowski';
String myPhoneNumber = '+48000000000';

Creating custom UI buttons

Below is an example of a custom UI button I used for calling functions. You can create any button that you wish, this is just an example.

class UrlLauncherButton extends StatelessWidget {
const UrlLauncherButton({super.key, required this.text, this.onPressed});

final String text;
final void Function()? onPressed;

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: SizedBox(width: 200, height: 40, child: Center(child: Text(text))),
);
}
}

Launching file

Create a Future<void> for each launch that you need. I suggest creating a separate file for example url_launches.dart to keep it all nice and tidy.

Launch email in app

This future launches an email in your main email app

Future<void> launchEmail() async {
final String email = Uri.encodeComponent("test@gmail.com");
final Uri mail = Uri.parse("mailto:$email");

try {
final bool launched = await launchUrl(mail);
if (launched) {
// email app opened
} else {
// email app is not opened
throw Exception('Could not launch email app');
}
} on PlatformException catch (e) {
throw Exception('Error launching email: $e');
}
}

If you want to add a default subject or body to the mail you have to parse it in the Uri like, bellow is an example:

Future<void> launchEmail() async {
final String email = Uri.encodeComponent("test@gmail.com");
final String subject = Uri.encodeComponent("Mail subject");
final String body = Uri.encodeComponent("Mail body");
final Uri mail = Uri.parse("mailto:$email?subject=$subject&body=$body");

try {
final bool launched = await launchUrl(mail);
if (launched) {
// email app opened
} else {
// email app is not opened
throw Exception('Could not launch email app');
}
} on PlatformException catch (e) {
throw Exception('Error launching email: $e');
}
}

Launch a phone call

This future opens the default phone app with the phone number of your choice.

Future<void> launchCall({required String phoneNumber}) async {
final Uri urlParsed = Uri.parse('tel:$phoneNumber');

if (await canLaunchUrl(urlParsed)) {
await launchUrl(urlParsed);
} else {
throw 'Could not launch call to: $phoneNumber';
}
}

Launch SMS message:

This future on the other hand opens up the default messages app with a blank message.

Future<void> launchSMS({required String phoneNumber}) async {
final Uri urlParsed = Uri.parse('sms:$phoneNumber');

if (await canLaunchUrl(urlParsed)) {
await launchUrl(urlParsed);
} else {
throw 'Could not launch sms to: $phoneNumber';
}
}

Launch website

Bellow are two options of opening a website, the first is in an in app browser.

Future<void> launchUrlSite({required String url}) async {
final Uri urlParsed = Uri.parse(url);

if (await canLaunchUrl(urlParsed)) {
await launchUrl(urlParsed);
} else {
throw 'Could not launch $url';
}
}

The second is in an external browser.

Future<void> launchUrlSiteBrowser({required String url}) async {
final Uri urlParsed = Uri.parse(url);

if (await canLaunchUrl(urlParsed)) {
await launchUrl(urlParsed, mode: LaunchMode.externalApplication);
} else {
throw 'Could not launch $url';
}
}

All done…

Adding functions to buttons

Now you can add the futures to your buttons like bellow, again this is just an example, and you are all done!

Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
UrlLauncherButton(
text: 'Launch Email',
onPressed: () => launchEmail(),
),
UrlLauncherButton(
text: 'Launch SMS',
onPressed: () => launchSMS(phoneNumber: myPhoneNumber),
),
UrlLauncherButton(
text: 'Launch Phone Call',
onPressed: () => launchCall(phoneNumber: myPhoneNumber),
),
UrlLauncherButton(
text: 'Launch url in app',
onPressed: () => launchUrlSite(url: httpsLink),
),
UrlLauncherButton(
text: 'Launch url in external app',
onPressed: () => launchUrlSiteBrowser(url: httpsLink),
),
],
),

Disclaimer

Don’t panic if calling the phone number or opening the mail app doesn’t work from the simulator, not all simulators have an e-mail and phone app installed, my suggestion is to try this on a real device.

Conclusion

As you can see adding url launches is not that difficult, just follow the steps above and you are all set to launch!

For the full source code visit the repository below.

If you would like to explore further functionalities of this package then please let me know in the response!

Outcome

Bellow is a gif with the outcome:

Example

Have any thoughts? Have a different method you would like to share? Leave a response!

--

--

Filip Doganowski
Tech Blog

Passionate Flutter Developer, Project Manager and Content Creator, visit my website: https://flutterdog.com