Shalitha Suranga Programmer | Author of Neutralino.js | Technical Writer

Using custom Chrome tabs in Flutter with the flutter_custom_tabs plugin

11 min read 3156

using-custom-chrome-tabs-flutter-with-flutter-custom-tabs-plugin

Mobile application developers often need to display webpages within their applications. The simplest way to show a webpage is to open the particular webpage in the user’s default web browser, but this has some obvious drawbacks.

For example, when the user opens a URL in a browser via your application, the particular action suddenly switches the current application context and launches the browser application, so it’s not user-friendly — and the browser UI is not customizable, either. Platform-specific webview components also let developers render web content, but webviews typically don’t share browsing states with the other web browsers and don’t include the latest web APIs.

The Chromium open-source browser solved this URL navigation problem by offering the Custom Tabs feature in 2015. Now, many major Android browsers implement the Custom Tabs protocol.

What is the Custom Tabs feature?

The Custom Tabs feature lets mobile app developers launch a webpage in a customizable browser instance that shares the same cookie jar and permissions model with the original browser application. The flutter_custom_tabs package offers a cross-platform solution for implementing Chrome Custom Tabs on Android and a Safari View Controller-based, Custom Tabs-like feature on iOS.

In this post, we will discuss every feature that flutter_custom_tabs offers on the Android platform via the following sections:

flutter_custom_tabs features

The flutter_custom_tabs package lets developers launch a URL on Chrome Custom Tabs on Android and Safari View Controller on iOS. The package includes many impressive features, which we’ll review in this section.

Flexible, full-featured, and minimal API

This package offers a simple API function like the url_launcher package to use Custom Tabs with a very flexible configuration object that covers almost all native Android Custom Tabs features. You can easily configure the browser toolbar, activity launcher animations, and some browser features via the library configuration object.

Cross-platform support

Chrome Custom Tabs is a feature introduced for the Android platform, but this package offers a similar feature on the iOS platform via the native Safari View Controller API. flutter_custom_tabs even works with the Flutter web platform by opening a new browser tab as a web-based Custom Tabs alternative via the url_launch_package.

Error handling

Chrome Custom Tabs requires the Chrome browser, another Custom Tabs-supported browser, or at least a browser app to launch a webpage. When there is no browser present in the system, this library cannot accomplish its task. You can handle such errors easily with Dart try-catch blocks.

Flutter Chrome Custom Tabs tutorial

Now we know the flutter_custom_tabs package’s highlighted features. Let’s install it into a Flutter project and try all supported features.



Setting up the flutter_custom_tabs package

You can either test the upcoming code examples with a new Flutter project or use the code examples directly in an existing project.

If you plan to create a new project, create one with the following command:

flutter create customtabs
cd customtabs

Now we can add flutter_custom_tabs to the dependencies list of the pubspec.yaml file and link the external package by running the following command:

flutter pub get flutter_custom_tabs 

Make sure that your dependencies list includes the newly linked package:

dependencies:
  flutter:
    sdk: flutter
  flutter_custom_tabs: ^1.0.4

  # --- Other dependencies ---

Next, run the project with the flutter run command to install the newly linked package and run the app.

You will see the default Flutter app once you run flutter run if the plugin installation was successful. You can leave the application running and test the upcoming code snippets, thanks to Flutter’s hot reloading feature.

Launching a URL with the basic syntax

Let’s launch a URL with Chrome Custom Tabs with no extra configuration to get started with this package. Add the following code to the lib/main.dart file.


More great articles from LogRocket:


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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Tabs Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue
      ),
      home: Home()
    );
  }
}

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom Tabs Demo'),
      ),
      body: Center(
        child: TextButton(
          child: const Text('Open GitHub', style: TextStyle(fontSize: 20)),
          onPressed: () => _launchURL(),
        ),
      ),
    );
  }

  void _launchURL() async {
    try {
      launch('https://github.com');
    }
    catch(e) {
      debugPrint(e.toString());
    }
  }
}

Here, we used the launch async function from the flutter_custom_tabs package to open a Chrome instance via the Custom Tabs feature. We used a typical Dart try-catch error-handling approach to detect Custom Tabs initialization issues.

Once you run the above code and click on the Material text button (ours reads Open GitHub), the app will open the GitHub website in Custom Tabs, as shown below.

Using github in flutter custom tabs
Custom Tabs with the default configuration

As shown in the above preview, I got the GitHub dashboard without signing in, since I already signed in to the GitHub website via Chrome  —  you will see all Custom-Tabs-launched websites the same as you see them in your Chrome browser because of the shared browser storage model (i.e., cookies, settings, etc.). You can go back to your app quickly with a single tap on the left side close button, or you can press the back button several times, depending on your browsing depth.

Customizing the toolbar via Android Intent

Even though Custom Tabs use the same installed Chrome browser, it lets developers customize the primary UI elements, such as the toolbar. The Custom Tabs API passes these configuration details to Chrome via the well-known Android Intent object. The launch function accepts an optional configuration object for Custom Tabs customization.

For example, we can change the toolbar background color with the toolbarColor property. Update your _launchURL function source with the following code snippet:

void _launchURL() async {
  try {
    launch('https://github.com',
      customTabsOption: CustomTabsOption(
        toolbarColor: Colors.blue
      )
    );
  }
  catch(e) {
    debugPrint(e.toString());
  }
}

Now you will get a blue-color toolbar for the Chrome instance, as shown in the following preview:

creating blue toolbar in flutter custom tabs
Custom Tabs with a hard-coded toolbar color

Here, we hard-coded the Colors.blue value for the toolbar color, but you can always apply your app theme’s primary color from the context reference with the Theme.of() function call, as shown below:

void _launchURL(BuildContext context) async {
    try {
      launch('https://github.com',
        customTabsOption: CustomTabsOption(
          toolbarColor: Theme.of(context).primaryColor,
        )
      );
    }
    catch(e) {
      debugPrint(e.toString());
    }
  }

Then, you also need to pass the context reference from the button press callback:

onPressed: () => _launchURL(context)

Here is the complete source code for using your theme’s primary color for Custom Tabs:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Tabs Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal
      ),
      home: Home()
    );
  }
}

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom Tabs Demo'),
      ),
      body: Center(
        child: TextButton(
          child: const Text('Open GitHub', style: TextStyle(fontSize: 20)),
          onPressed: () => _launchURL(context),
        ),
      ),
    );
  }
  void _launchURL(BuildContext context) async {
    try {
      launch('https://github.com',
        customTabsOption: CustomTabsOption(
          toolbarColor: Theme.of(context).primaryColor,
        )
      );
    }
    catch(e) {
      debugPrint(e.toString());
    }
  }
}

Once you run the above code, you will see the teal primary theme color we chose in the Custom Tab toolbar, as shown in the following preview:

Using flutter custom tabs theme primary color
Flutter Custom Tabs is using the application theme’s primary color

The showPageTitle property lets you control the visibility of the webpage title on the toolbar. The following configuration object asks Custom Tabs to show the webpage title:

customTabsOption: CustomTabsOption(
        // --- Other options ---
        // ...
        showPageTitle: true,
      )

Now we can see the webpage title as follows:

custom chrome tab showing website title
Flutter Custom Tabs with the webpage title

This package offers two more configuration properties for toolbar-related customizations. The enableDefaultShare and enableUrlBarHiding properties help show or hide the sharing menu item and show/hide the toolbar while scrolling, respectively.

Customizing Android activity animations

The Android platform typically plays a system animation during every activity launch. Chrome Custom Tabs also inherits the same system animation by default. The flutter_custom_tabs package offers a very flexible way to customize the activity animation of the Chrome Custom Tab via the CustomTabsSystemAnimation and CustomTabsAnimation classes.

This package offers two inbuilt activity animations: slideIn and fade. You can activate the slideIn pre-built animation with the following code snippet:

customTabsOption: CustomTabsOption(
          // --- Other options ---
          // ....
          animation: CustomTabsSystemAnimation.slideIn(),
        )

Now you will see the slideIn animation as shown in the following preview:

Using the custom chrome slidein
Flutter Custom Tabs with the slideIn transition animation

We can use the fade animation by adding the animation: CustomTabsSystemAnimation.fade() configuration.

Using the custom fade animation
Flutter Custom Tabs with the fade transition animation

This package is so flexible  —  it lets you use any Android framework core animation instead of the pre-built library animations. For example, you can build a custom animation by using the following configuration object:

import 'package:flutter_custom_tabs_platform_interface/flutter_custom_tabs_platform_interface.dart'; // Import CustomTabsAnimation
customTabsOption: CustomTabsOption(
          // --- Other options ---
          // ...
          animation: const CustomTabsAnimation(
            startEnter: 'android:anim/screen_rotate_minus_90_enter',
            startExit: 'android:anim/fade_out',
            endEnter: 'android:anim/screen_rotate_minus_90_enter',
            endExit: 'slide_down/fade_out',
          ),
        )

Now you will see a different rotating transition animation than the previous pre-built library animations:

Using user-defined rotation transition animation
Flutter Custom Tabs with a user-defined rotation transition animation

You can provide Android framework core animation identifiers for the CustomTabsAnimation constructor, and browse all Android framework core animations on offer.

Each animation constructor parameter has the following definition:

  • startEnter: Enter animation for Custom Tabs
  • startExit: Exit animation for the application activity that launched Custom Tabs
  • endEnter: Enter animation for the application that launched Custom Tabs
  • endExit: Exit animation for Custom Tabs

Try to make your own transition animations from Android framework core animations! Just make sure to implement your animations without negatively or drastically affecting the user experience.

Advanced Custom Tabs configurations

The above are common features that every Flutter developer needs to configure Chrome Custom Tabs. The flutter_custom_tabs package also supports some advanced configurations for specific requirements. For example, you can prioritize fallback browsers if Chrome is not present on the user’s device with the extraCustomTabs array.

The following configuration prioritizes Mozilla Firefox and then Microsoft Edge if Chrome is not present on the user’s device by referring Android package names:

customTabsOption: CustomTabsOption(
          extraCustomTabs: const <String>[
            'org.mozilla.firefox',
            'com.microsoft.emmx'
           ],
        )

Also, this package lets you enable and disable Google Play Instant Apps in Custom Tabs via the enableInstantApps boolean configuration property. For example, the following configuration activates the Instant Apps feature on Custom Tabs:

>customTabsOption: CustomTabsOption(
          enableInstantApps: true
        )

This package also lets you send some header values with the HTTP request, as shown below:

customTabsOption: CustomTabsOption(
          // --- Other options ---
          // ...
          headers: {
            'content-type': 'text/plain'
          }
        )

Note that these header values need to be CORS safelisted request headers  —  otherwise, you need to configure Google Digital Asset Links with your domain name to send arbitrary request headers.

iOS and web support configuration

The flutter_custom_>tabs package supports Android, iOS, and web platforms. On Android, it uses Chrome or other fallback browsers via the underlying CustomTabsLauncher platform-specific Kotlin library.

On iOS, it uses the system-included SFSafariViewController class directly via Flutter method channel APIs for opening a customized Safari instance. On the web platform, it opens a new browser tab via the url_launcher_web package.

The web version of flutter_custom_tabs is not customizable, since we can’t change the browser UI with client-side JavaScript. But, we can customize the Safari instance on iOS in a somewhat similar fashion to Custom Tabs. Look at the following configuration object:

>customTabsOption: CustomTabsOption(
        // --- Other options ---
        // ...
        safariVCOption: SafariViewControllerOption(
          preferredBarTintColor: Colors.blue,
          preferredControlTintColor: Colors.white,
          barCollapsingEnabled: true,
          entersReaderIfAvailable: true,
          dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,        
        ),
      )

The above configuration sets the following Safari UI customizations:

  • Use the blue color for the toolbar background with the preferredBarTintColor property
  • Use the white color for the toolbar elements with the preferredControlTintColor property
  • Auto-collapse the toolbar when the user scrolls with the barCollapsingEnabled property
  • Activate the reader mode automatically with the entersReaderIfAvailable property
  • Use the Close button to go back to the application with the dismissButtonStyle property

Custom Tabs vs. Default browser vs. Webview

Custom Tabs is not the only way to render web content on Flutter applications — we have Flutter packages to open the default browser and implement in-app webviews, too. Let’s discuss the pros and cons of launching the default browser and using webview by comparing each option with the Custom Tabs solution.

Point of comparison Custom Tabs Default browser Webview
Initialization Offers the fastest initialization time with native Android and Chrome Custom Tabs performance optimizations Webpage initialization is slow because the default web browser doesn’t use specific initialization performance optimizations as Custom Tabs Webpage initialization can be boosted with various performance tweaks, but webview components don’t typically support full web APIs and browser features as web browsers do
Customizability Able to customize the UI (Toolbar and menu) according to the Flutter application theme Not able to customize the UI, since the URL launching process is controlled by the Android system  —  not explicitly by the developer Highly customizable if the webview resides in an activity created by the developer
UX/Navigating between browser and app Inbuilt, user-friendly navigation support between the application and Custom Tab The default browser may appear as a completely different app compared to the Flutter app user experience, and the user typically needs to find ways to close the browser app to return to your app again Developers can offer the same user experience as the other native parts of the app with various UI and internal webview features because they can customize the webview as they need
Cookie and permissions sharing Shares the cookie jar and permission model, so users can see the exact same website state on both Chrome and Custom Tabs instances Use the same cookie jar and permission model because URLs are launched in the same default browser in the system Neither the cookie jar nor the permission model is shared among browsers and webview components. The user may have to sign in twice into webpages from the browser and webview, unlike with Custom Tabs
Availability Available for Flutter developers via flutter_custom_tabs and flutter_web_browser plugins Available for Flutter developers via the url_launcher plugin Available for Flutter developers via the url_launcher plugin (very limited customization) and webview_flutter plugin (flexible customization)

Let’s summarize the above comparison table according to your application development needs.

If you only need to display a webpage, consider using Custom Tabs rather than launching the default browser for a better user experience. If you need to present your own web content with native-web, communication-bridge-like advanced customizations, the webview-oriented approach gives you complete flexibility and support.

Think twice before using the default browser option  — it does change the application context, affecting the user experience.

Best practices for implementing Custom Tabs

Development best practices always help us to build high-quality software systems that users appreciate and may recommend to other users. As you have already experienced, implementing Custom Tabs is very easy with the flutter_custom_tabs package. Even though the implementation is not complex, we need to think about best practices for achieving better application quality.

Consider the following best practices while you are working with Custom Tabs in Flutter.

  • Try to offer the same look and feel in Custom Tabs as you do in the application — including animations and colors similar to your application screens
  • Always test fallback options: Chrome and some other popular browsers support Custom Tabs, but in some cases, users may not use Chrome or a browser that supports Custom Tabs — or the user may not have a web browser application. Therefore, check whether your application will use the default browser or a webview implementation in such scenarios
  • Don’t redefine the same CustomTabsOption object in many places by following the DRY programming principle  —  implement a shared function for launching all Custom Tabs, as we created the _launchURL function before
  • Add cross-platform support and test on real devices. Make sure to configure flutter_custom_tabs for iOS by using the safariVCOption configuration property

Take a look at the following complete configuration for the final bullet point:

void _launchURL(BuildContext context) async {
  final theme = Theme.of(context);
  try {
    launch('https://github.com',
      // Android Custom Tabs config
      customTabsOption: CustomTabsOption(
        showPageTitle: true,
        toolbarColor: theme.primaryColor,
        animation: CustomTabsSystemAnimation.fade(),
        // fallback options
        extraCustomTabs: const <String>[
          'org.mozilla.firefox',
          'com.microsoft.emmx',
        ],
        headers: {
          'content-type': 'text/plain'
        }
      ),
      // iOS Safari View Controller config
      safariVCOption: SafariViewControllerOption(
        preferredBarTintColor: theme.primaryColor,
        preferredControlTintColor: Colors.white,
        barCollapsingEnabled: true,
        entersReaderIfAvailable: false,
        dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,
      ),
    );
  }
  catch(e) {
    // Handle the URL launching failure here
    debugPrint(e.toString());
  }
}

You can download a complete sample Flutter Custom Tabs project source code from my GitHub repository.

Conclusion

In this tutorial, we’ve discussed almost all the features that the flutter_custom_tabs provides. This package provides a simple function to integrate Custom Tabs in Flutter applications. Even though it offers a minimal Dart function for working with Custom Tabs, it lets you make almost all customizations you need using Chrome Custom tabs in Flutter.

However, flutter_custom_tabs has a few issues that need to be fixed. For example, some configuration options like enableDefaultShare don’t work as expected. Also, there is no option for adding additional action/menu items to a particular Custom Tab, even though the native Android API supports custom action/menu items in Custom Tabs. I also noticed that the Custom Tab closing animation didn’t work properly. Due to these issues, Flutter developers started supporting some alternative plugins, like flutter_web_browser.

But, overall, the flutter_custom_tabs package is still the best Flutter Custom Tabs plugin out there, and it offers a flexible and fully-featured interface for developers. It even provides you Custom Tabs-like implementations for both Flutter web and iOS. This package has a high popularity score on the Dart packages registry and has a well-structured codebase — hence, we can use flutter_custom_tabs in production apps without any issue.

Package maintainers will add the missing features and fix existing issues soon to support the entire Flutter developer community.

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

.
Shalitha Suranga Programmer | Author of Neutralino.js | Technical Writer

One Reply to “Using custom Chrome tabs in Flutter with the flutter_custom_tabs…”

  1. Hi, I’m new to flutter.
    She developed a pwa in react.

    I am looking for alternatives to be able to create the app for the apple store, and customtabs, it seems interesting to me.

    Tried using webview, but it gives me a lot of trouble using social login.

    With custom tabs, is it possible to start the custom tab, when the first widget loads?

    That is, the custom tabs opens without pressing the button.

    Thanks.

    Norbert.

Leave a Reply