How to Launch URLs in Flutter using the url_launcher package

Flutter Jul 10, 2023

This post will show you how to use the url_launcher package in Flutter to open URLs in your application. We will be installing the package, setting up a basic Flutter application, and implementing the code to launch URLs. We will also go over the canLaunchUrl function, which helps us to check if a URL can be opened without actually opening it. By following along, you will be able to launch URLs in your Flutter application with ease.

Getting started

The application that we will build has a single page that shows a button. When the button is pressed we want to launch our URL. Here is the starting code of our main.dart file:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'URL Launcher Demo',
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('URL Launcher Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => {},
          child: Text('Launch URL'),
        ),
      ),
    );
  }
}

In this code snippet, we have a Flutter application that displays our HomePage widget. Inside the HomePage widget we display a Scaffoled widget that shows a Button with the text "Launch URL". At the moment to onPressed property of the button is set to an empty function.

flutter_application_showing_elevated_button

Installing url_launcher

To continue, we have to install the url_launcher package in our Flutter project. We can install the package by executing the following command: flutter pub add url_launcher.

After installing the package make sure that the package is underneath the dependencies inside your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  url_launcher: ^6.1.12

Now that the package is installed, we can start creating a function that will launch our URL.

Launching an URL

The url_launcher package has a function called launchUrl, with just this function alone we can already launch our URL. The launchUrl has the following parameters:

  1. url: This parameter specifies the URL that we want to launch. It should be an instance of the Uri class.
  2. mode: This parameter determines how the URL should be launched. It is an enum of type LaunchMode with the following possible values:
    • LaunchMode.platformDefault: The URL will be launched using the default method on the platform.
    • LaunchMode.inAppWebView: The URL will be launched in a WebView within the app.
    • LaunchMode.externalApplication: The URL will be passed to the operating system to be handled by another application, for example Google Chrome.
    • LaunchMode.externalNonBrowserApplication: The URL will be passed to the operating system to be handled by another non-browser application.
  3. webViewConfiguration: This parameter is only applicable if the mode is set to LaunchMode.webView. It allows you to configure the behavior of the WebView. You can provide an instance of the WebViewConfiguration class with desired settings such as enabling JavaScript, specifying headers, etc. The WebViewConfiguration class has various properties to customize the WebView's behavior.
  4. webOnlyWindowName: This parameter is only applicable if the mode is set to LaunchMode.webView and the URL is being launched in a new window. It specifies the name of the new window. The values provided should be of type String. If not provided, a default name will be used.

The simplest implementation is to provide only the URL inside the launchUrl function, this simple implementation will look like this:

_launchURL() async {
  Uri url = Uri.parse('https://codeonwards.com');

  try {
    await launchUrl(url);
  } catch (_) {
    throw 'Could not launch $url';
  }
}

In our _launchUrl function we start by creating our URL, we know now that it needs to be of type Uri. Creating a Uri from a String can be easily done in Dart by using the Uri.parse function. Once we have created our URL we pass it into the launchUrl function. The launchUrl function returns a Future so we use the await keyword to wait for the value. Because we have added the await keyword our function needs to be asynchronous. To make sure that we catch any problem we wrap the launchUrl function with a try-catch and throw a message.

By creating the following function our complete code looks like this:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'URL Launcher Demo',
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  _launchURL() async {
    Uri url = Uri.parse('https://codeonwards.com');

    try {
      await launchUrl(url);
    } catch (_) {
      throw 'Could not launch $url';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('URL Launcher Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: _launchURL,
          child: Text('Launch URL'),
        ),
      ),
    );
  }
}

Compared to the previous main.dart file we have added our _launchUrl function and assigned it to the onPressed property of our ElevatedButton. Now when we click the button our URL will launch:

flutter_launching_code_onwards_url

Check if URL can be launched

In the previous implemented functionality we used a try-catch block to handle potential errors when launching a URL. However, the canLaunchUrl function from the url_launcher package can improve this. The function allows us to check whether the given URL can be launched or not, without actually launching it. This can be useful in scenarios where you want to perform a conditional check before attempting to launch the URL. For example, you might want to disable or hide a button if the URL cannot be launched on the user's device.

In order to use this function we need to make platform-specific changes:

Android

For Android we want to make the following changes in the AndroidManifest.xml file, which can be found with the following path: codeonwards_demo/android/app/src/main/AndroidManifest.xml, where codeonwards_demo is the name of your project:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <queries>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
        </intent>
    </queries>
    <application ...>
</manifest>

In the above code snippet, we have added the <queries> element with all the elements inside to make sure that we can verify if at least one browser is available on Android devices. You do not have to make any changes in the <application> element, it is collapse in this code snippet, to make it easier to see the changes.

iOS

In iOS we have to make the following changes in the Info.plist file, which can be found with the following path: codeonwards_demo/ios/Runner/Info.plist, where codeonwards_demo is the name of your project:

<plist version="1.0">
    <dict>
        <key>LSApplicationQueriesSchemes</key>
        <array>
            <string>https</string>
        </array>
          ...
    </dict>
</plist>

In this code snippet, we added the LSApplicationQueriesSchemes key with and array that contains https as value. The other keys are left out to make it easier to notice the changes, you should not remove them.

If we do not make these changes we run into this error: component name for https://codeonwards.com is null.

Now we can make the following changes to our HomePage widget:

class HomePage extends StatelessWidget {
  _launchURL(BuildContext context) async {
    Uri url = Uri.parse('codeonwards.com');

    if (await canLaunchUrl(url)) {
      await launchUrl(url);
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            'Could not launch $url',
            textAlign: TextAlign.center,
          ),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('URL Launcher Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => _launchURL(context),
          child: Text('Launch URL'),
        ),
      ),
    );
  }
}

In the above code snippet we replaced the try-catch with an if statement that checks whether the URL can be launched using the canLaunchUrl function from the url_launcher package. If true, it will launch the URL otherwise it will show a SnackBar message. We changed the value of the url variable to codeonwards.com which is not a valid URL. Now when we run our code, we will see the following:

flutter_launching_code_onwards_url
This specific use case can also be done with the try-catch, but like said before the difference is that our application is not actually calling the functionality to launch the URL. As an addition the canLaunchUrl will also check if the user's device is able to launch any URL.

Conclusion

This tutorial explained how to use the url_launcher package in Flutter to launch URLs. We installed the package and set up a basic Flutter application. We used the launchUrl function to open the provided URL. We also learned about the canLaunchUrl function, which allows us to check if a URL can be opened without actually opening it. Therefore we made the necessary platform-specific changes for Android and iOS, and then modified our code to handle cases where the URL cannot be launched. Overall, the url_launcher package provides an easy way to open URLs in Flutter, and the canLaunchUrl function helps handle scenarios where the URL cannot be opened.

Tags