Updated June 2026. Tested on Flutter 3.x and Dart 3. Part of the Techalyst Flutter series.
Apps regularly need to hand off to another app: open a website, dial a number, start an email, drop a pin in maps. You do this with URL schemes, and in Flutter the url_launcher package turns any of them into a one-line call. The pattern is the same every time, only the URL changes.
Setup
Add url_launcher to pubspec.yaml. On Android there is one extra step: from Android 11 onward, the OS hides which apps are installed, so you declare the schemes you intend to launch in a <queries> block in AndroidManifest.xml. Add entries for https, tel, mailto and any others you use, otherwise the launch quietly fails on newer devices.
Opening a web link
The core call is launchUrl with a Uri. The launch mode decides where it opens:
import 'package:url_launcher/url_launcher.dart';
Future<void> openWebsite() async {
final uri = Uri.parse('https://techalyst.com');
if (!await launchUrl(uri, mode: LaunchMode.externalApplication)) {
throw Exception('Could not open $uri');
}
}
LaunchMode.externalApplication opens the device's browser. LaunchMode.inAppWebView keeps the user inside your app with a lightweight web view, which is nice for a quick page without leaving the flow. For a fully controllable embedded browser, you would reach for webview_flutter instead.
The other schemes
The only thing that changes for phone, email, SMS and maps is the Uri you build. Constructing it with named parts is cleaner than string concatenation and handles encoding for you.
// Phone call
launchUrl(Uri(scheme: 'tel', path: '+94771234567'));
// Email with a subject
launchUrl(Uri(
scheme: 'mailto',
path: 'hello@techalyst.com',
query: 'subject=Hello&body=Hi there',
));
// SMS
launchUrl(Uri(scheme: 'sms', path: '+94771234567'));
// Maps: open a location
launchUrl(Uri.parse('https://www.google.com/maps/search/?api=1&query=Colombo'));
tel and sms open the dialer and messaging app. mailto opens the mail composer with the fields prefilled. The maps URL opens whatever maps app the user prefers. Same launchUrl, different scheme.
Checking before you launch
There is also canLaunchUrl, meant to check whether anything can handle a URL before you try. It is genuinely useful, but be aware it relies on the same Android <queries> configuration, so a missing entry makes it return false even when an app exists. Many people skip the check and instead act on the boolean launchUrl returns, which tells you whether the launch actually succeeded. That avoids the trap of canLaunchUrl reporting false for the wrong reason.
Wrapping up
url_launcher is the single tool for sending users out to other apps. Build a Uri for what you want, https for the web, tel to dial, mailto to email, sms to text, a maps URL for directions, and pass it to launchUrl with the right LaunchMode. Remember the Android <queries> entries so it works on modern devices, and lean on the boolean from launchUrl rather than fighting canLaunchUrl. With that, every "open this in the proper app" feature is a couple of lines.
All comments ()
No comments yet
Be the first to leave a comment on this post.