Launching URLs in Flutter with url_launcher

A comprehensive guide to integrating external URL launching, phone calls, emails, and SMS in your Flutter applications with code examples and best practices.

What is url_launcher?

The url_launcher is Flutter's official plugin for launching URLs in external applications. It provides a unified API that works across multiple platforms, abstracting the platform-specific implementation details away from developers. With over 2.86 million downloads, it is one of the most widely used packages in the Flutter ecosystem.

When building cross-platform mobile applications, integrating with external services and native device capabilities is essential for creating seamless user experiences. The url_launcher package enables your Flutter app to interact with the device's native applications, keeping users within their preferred ecosystem while maintaining context within your application.

Key Capabilities

  • Opening URLs in external web browsers
  • Making phone calls directly from the app
  • Sending SMS messages with pre-filled content
  • Composing emails with recipients and subject lines
  • Launching native map applications
  • Opening files on desktop platforms

Supported Platforms

  • Android: SDK 21+ (Android 5.0 Lollipop and higher)
  • iOS: 12.0+
  • Linux, macOS, Windows: Desktop platforms
  • Web: Any modern browser

Installation and Configuration

Adding the Dependency

To add url_launcher to your Flutter project, run the following command:

flutter pub add url_launcher

Or manually add to your pubspec.yaml:

dependencies:
 url_launcher: ^6.3.2

Then import the package:

import 'package:url_launcher/url_launcher.dart';

Platform-Specific Configuration

iOS Configuration

For iOS, add URL schemes to the LSApplicationQueriesSchemes array in your Info.plist file:

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

This configuration is required because iOS restricts which URL schemes apps can query for availability. Without proper declaration, canLaunchUrl() will return false for schemes not listed.

Android Configuration

For Android 11 (API 30) and higher, declare URL schemes in AndroidManifest.xml:

<queries>
 <intent>
 <action android:name="android.intent.action.VIEW" />
 <data android:scheme="sms" />
 </intent>
 <intent>
 <action android:name="android.intent.action.VIEW" />
 <data android:scheme="tel" />
 </intent>
</queries>

This requirement exists starting with Android 11 due to package visibility changes in the Android platform.

Supported URL Schemes
SchemeExamplePurpose
https:https://flutter.devOpen web URLs in browser
mailto:mailto:[email protected]?subject=HelloOpen email client
tel:tel:+1-555-010-999Make phone call
sms:sms:5550101234Send SMS message
file:file:/path/to/fileOpen local files (desktop)

Core API Methods

canLaunchUrl

The canLaunchUrl() method checks whether the device can handle a given URL:

final Uri url = Uri.parse('https://flutter.dev');
final bool canLaunch = await canLaunchUrl(url);

This method is useful for:

  • Checking feature availability before attempting to launch
  • Conditionally enabling UI elements based on capability
  • Providing fallback behavior when launching isn't possible

launchUrl

The launchUrl() method attempts to launch the given URL:

final Uri url = Uri.parse('https://flutter.dev');
if (await launchUrl(url)) {
 // URL launched successfully
} else {
 // Failed to launch URL
}

The method accepts an optional LaunchMode parameter to control how the URL is opened.

Launch Modes

Understanding LaunchMode

The url_launcher package provides several LaunchMode options:

LaunchMode.externalApplication

Opens the URL in the default external application:

launchUrl(url, mode: LaunchMode.externalApplication);

Use when: You want to keep users in the native apps they prefer, opening external documents or files. This is ideal for mobile app development projects where users need access to full browser features or native applications.

LaunchMode.inAppWebView

Opens the URL within the application using an embedded web view:

launchUrl(url, mode: LaunchMode.inAppWebView);

Use when: You want to keep users engaged within your app while browsing lightweight content. This mode requires the Custom Tabs service to be available on Android.

LaunchMode.inAppBrowserView

Uses the in-app browser view pattern for a more integrated experience:

launchUrl(url, mode: LaunchMode.inAppBrowserView);

LaunchMode.platformDefault

Uses the platform's default behavior. This is the default mode when no mode is specified.

Practical Code Examples

Opening a Web Page

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class WebLauncherExample extends StatelessWidget {
 final Uri _url = Uri.parse('https://flutter.dev');

 Future<void> _launchUrl() async {
 if (!await launchUrl(_url)) {
 throw Exception('Could not launch $_url');
 }
 }

 @override
 Widget build(BuildContext context) {
 return Scaffold(
 body: Center(
 child: ElevatedButton(
 onPressed: _launchUrl,
 child: const Text('Open Flutter Website'),
 ),
 ),
 );
 }
}

This pattern is commonly used in Flutter applications to link to documentation, privacy policies, or external resources. For building complete web-integrated mobile solutions, proper URL launching is essential for seamless user experiences.

Making a Phone Call

class PhoneCallerExample extends StatefulWidget {
 const PhoneCallerExample({super.key});

 @override
 State<PhoneCallerExample> createState() => _PhoneCallerExampleState();
}

class _PhoneCallerExampleState extends State<PhoneCallerExample> {
 bool _hasCallSupport = false;
 String _phoneNumber = '';

 @override
 void initState() {
 super.initState();
 canLaunchUrl(Uri(scheme: 'tel', path: '123')).then((bool result) {
 setState(() {
 _hasCallSupport = result;
 });
 });
 }

 Future<void> _makePhoneCall(String phoneNumber) async {
 final Uri launchUri = Uri(scheme: 'tel', path: phoneNumber);
 await launchUrl(launchUri);
 }

 @override
 Widget build(BuildContext context) {
 return Scaffold(
 body: Padding(
 padding: const EdgeInsets.all(16.0),
 child: Column(
 children: [
 TextField(
 onChanged: (String value) => _phoneNumber = value,
 decoration: const InputDecoration(labelText: 'Phone number'),
 ),
 const SizedBox(height: 16),
 ElevatedButton(
 onPressed: _hasCallSupport ? () => _makePhoneCall(_phoneNumber) : null,
 child: _hasCallSupport 
 ? const Text('Make Phone Call') 
 : const Text('Calling not supported'),
 ),
 ],
 ),
 ),
 );
 }
}

This implementation pattern is essential for business applications that need to provide direct customer contact options. Modern AI-powered mobile applications often integrate voice and communication features for enhanced customer engagement.

Sending an Email

String? encodeQueryParameters(Map<String, String> params) {
 return params.entries
 .map((e) => '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
 .join('&');
}

Future<void> _sendEmail() async {
 final Uri emailUri = Uri(
 scheme: 'mailto',
 path: '[email protected]',
 query: encodeQueryParameters(<String, String>{
 'subject': 'Support Request',
 'body': 'Please describe your issue...',
 }),
 );

 if (await canLaunchUrl(emailUri)) {
 await launchUrl(emailUri);
 }
}

Sending an SMS

Future<void> _sendSms(String phoneNumber, String message) async {
 final Uri smsUri = Uri(
 scheme: 'sms',
 path: phoneNumber,
 queryParameters: <String, String>{'body': message},
 );

 if (await canLaunchUrl(smsUri)) {
 await launchUrl(smsUri);
 }
}

These patterns are widely used in customer service features within mobile applications for businesses that need to provide multiple communication channels. Pairing these capabilities with intelligent automation workflows can create seamless customer support experiences.

Best Practices

Error Handling

Always handle potential errors when launching URLs:

Future<void> _safeLaunch(Uri url) async {
 try {
 if (await canLaunchUrl(url)) {
 await launchUrl(url);
 } else {
 debugPrint('Cannot launch URL: $url');
 }
 } catch (e) {
 debugPrint('Error launching URL: $e');
 }
}

User Experience Considerations

  • Check capabilities first: Use canLaunchUrl to determine if a feature is available before enabling UI elements
  • Provide fallbacks: When a URL scheme isn't available, offer alternative ways to accomplish the task
  • Choose appropriate launch modes: Consider whether in-app or external launching better serves the user
  • Handle errors gracefully: Provide clear feedback when URLs cannot be launched

Security Considerations

  • Validate URLs: Ensure URLs are properly formatted and from trusted sources
  • Prefer HTTPS: Use HTTPS URLs for web content to ensure secure connections
  • Sanitize user input: Validate any URLs constructed from user input
  • Be cautious with deep links: Ensure deep link actions are the user's intended action

Following these best practices ensures your cross-platform applications are both secure and user-friendly. For teams building enterprise-grade mobile solutions, proper URL handling is a critical component of app security.

Common Use Cases

Contact Pages

Enable users to contact you via phone, email, SMS, or social media with a single tap.

E-commerce

Open payment providers, shipping tracking, review platforms, and social sharing.

Content Sharing

Share content via social media, messaging apps, or email with pre-filled messages.

Navigation

Launch map applications with coordinates or addresses for directions.

Troubleshooting Common Issues

URL Not Launching

  1. Check platform configuration: Verify iOS Info.plist and AndroidManifest.xml include required schemes
  2. Use canLaunchUrl first: Confirm the URL scheme is recognized
  3. Check for installed apps: Some schemes require specific apps to be installed
  4. Verify URL format: Ensure URLs are properly formatted with Uri.parse()
  5. Test on physical devices: Simulators may not have all apps installed

iOS Simulator Limitations

iOS simulators do not have default email or phone apps installed, so URLs with mailto: or tel: schemes will not launch. Always test these features on physical iOS devices.

URL Encoding Issues

For URL schemes other than http and https, always use encodeQueryParameters() for query parameters to avoid encoding issues with spaces and special characters.

For more Flutter development tutorials, explore our guide on creating listviews in Flutter to build comprehensive mobile interfaces with proper navigation patterns.

Conclusion

The url_launcher package provides Flutter developers with a powerful, cross-platform solution for integrating external application launching into their apps. By following proper installation procedures, configuring platform-specific requirements, and implementing best practices for error handling and user experience, you can seamlessly connect your Flutter applications with external services and native device capabilities.

Whether you're building a contact page, implementing sharing functionality, or integrating with external services, url_launcher offers the flexibility and reliability needed to create polished, professional mobile applications.

For teams looking to implement robust URL launching and other native integrations in their Flutter projects, partnering with experienced mobile development specialists ensures clean implementation and adherence to platform best practices.


Sources

  1. Pub.dev - url_launcher package - Official Flutter package documentation with installation, API reference, and platform-specific configuration
  2. LogRocket Blog - Launching URLs in Flutter with url_launcher - Tutorial with practical examples for building contact pages with URL launching functionality
  3. Cybrosys - How to Install & Configure Flutter url_launcher - Detailed configuration guide with iOS and Android manifest updates