flutter_custom_tabs
A Flutter plugin for mobile apps to launch a URL in Custom Tabs.
The plugin allows you to add the browser experience that Custom Tabs provides to your mobile apps.
In version 2.0, the plugin expands the support for launching a URL in mobile apps:
- Launch a URL in an external browser.
- Launch a deep link URL.
Android | iOS | Web | |
---|---|---|---|
Support | SDK 19+ | 12.0+ | Any |
Implementation | Custom Tabs | SFSafariViewController | url_launcher |
Getting Started
Add flutter_custom_tabs
to the dependencies of your pubspec.yaml
.
dependencies:
flutter_custom_tabs: ^2.4.0
Important
v2.0.0 includes breaking changes from v1.x. Please refer to the migration guide when updating the plugin.
Requirements
iOS
- Xcode 15.0 and above.
Android
- Android Gradle Plugin v7.4.0 and above.
- Kotlin v1.7.0 and above.
plugins | buildscript |
|
|
Usage
You can launch a web URL similar to url_launcher
and specify options to customize appearance and behavior.
Android | iOS |
---|---|
![]() |
![]() |
Basic Usage
import 'package:flutter/material.dart';
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
void _launchUrl(BuildContext context) async {
final theme = Theme.of(context);
try {
await launchUrl(
Uri.parse('https://flutter.dev'),
customTabsOptions: CustomTabsOptions(
colorSchemes: CustomTabsColorSchemes.defaults(
toolbarColor: theme.colorScheme.surface,
),
shareState: CustomTabsShareState.on,
urlBarHidingEnabled: true,
showTitle: true,
closeButton: CustomTabsCloseButton(
icon: CustomTabsCloseButtonIcons.back,
),
),
safariVCOptions: SafariViewControllerOptions(
preferredBarTintColor: theme.colorScheme.surface,
preferredControlTintColor: theme.colorScheme.onSurface,
barCollapsingEnabled: true,
dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,
),
);
} catch (e) {
// If the URL launch fails, an exception will be thrown. (For example, if no browser app is installed on the Android device.)
debugPrint(e.toString());
}
}
See the example app for more complex examples.
Usage of the lightweight version
This package supports a wide range of Custom Tabs customizations,
but we have introduced a lightweight URL launch for users who don't need as much in v2.0.0.
Note
On Android, the lightweight version prefers launching the default browser that supports Custom Tabs over Chrome.
import 'package:flutter/material.dart';
import 'package:flutter_custom_tabs/flutter_custom_tabs_lite.dart';
void _launchUrl(BuildContext context) async {
final theme = Theme.of(context);
try {
await launchUrl(
Uri.parse('https://flutter.dev'),
options: LaunchOptions(
barColor: theme.colorScheme.surface,
onBarColor: theme.colorScheme.onSurface,
barFixingEnabled: false,
),
);
} catch (e) {
// If the URL launch fails, an exception will be thrown. (For example, if no browser app is installed on the Android device.)
debugPrint(e.toString());
}
}
Custom Tabs Customization
Option | Android (CustomTabsOptions ) |
iOS (SafariViewControllerOptions ) |
LaunchOptions |
---|---|---|---|
Change background color of app/bottom bar | ✅ | ✅ | ✅ |
Change color of controls on app/bottom bar | - (Automatically adjusted by Custom Tabs) |
✅ | ✅ |
Change background color of system navigation bar | ✅ | - | ✅ |
Change color of system navigation divider | ✅ | - | ✅ |
Hide(Collapse) the app bar by scrolling | ✅ | ✅ | ✅ |
Add sharing action for web pages | ✅ | - | ✅ (always added on Android) |
Change visibility of web page title | ✅ | - | ✅ (always shown on Android) |
Change the availability of Reader mode | - | ✅ | Not provided |
Change appearance of close button | ✅ (Icon, position) |
✅ (Predefined button styles) |
Not provided |
Change the availability of Instant Apps | ✅ | - | Not provided |
Change availability of bookmarks button | ✅ | - | Not provided |
Change availability of download button | ✅ | - | Not provided |
Enable App-specific history | ✅ | - | ✅ (always enabled on Android) |
Change animation style | ✅ | ✅ (Predefined modal presentation styles) |
Not provided |
Prefer the default browser over Chrome | ✅ | - | Not provided |
Pass HTTP headers | ✅ | - | Not provided |
Partial display | ✅ | ✅ (bottom sheet only) |
Not provided |
Support status in flutter_custom_tabs
:
- ✅: Supported.
-
: Option not provided by Custom Tabs implementation.
Advanced Usage
Deep Linking
Supports launching a deep link URL.
(If a native app that responds to the deep link URL is installed, it will directly launch it. otherwise, it will launch a Custom Tab.)
import 'package:flutter/material.dart';
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
// or import 'package:flutter_custom_tabs/flutter_custom_tabs_lite.dart';
Future<void> _launchDeepLinkUrl(BuildContext context) async {
final theme = Theme.of(context);
await launchUrl(
Uri.parse('https://www.google.com/maps/@35.6908883,139.7865242,13z'),
prefersDeepLink: true,
customTabsOptions: CustomTabsOptions(
colorSchemes: CustomTabsColorSchemes.defaults(
toolbarColor: theme.colorScheme.surface,
),
),
safariVCOptions: SafariViewControllerOptions(
preferredBarTintColor: theme.colorScheme.surface,
preferredControlTintColor: theme.colorScheme.onSurface,
),
);
}
Launch in an external browser
By default, if no mobile platform-specific options are specified, a URL will be launched in an external browser.
Tip
Android: CustomTabsOptions.externalBrowser
supports HTTP request headers.
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
Future<void> _launchInExternalBrowser() async {
await launchUrl(Uri.parse('https://flutter.dev'));
}
Partial display
Partial display allows web content to appear in a sheet instead of taking up the full screen. This creates a more integrated experience where users can view and interact with web content while still seeing parts of your app.
- Android: Supports bottom sheets (Chrome 107+, portrait mode) and side sheets (Chrome 120+, landscape mode or large screens).
- For implementation details, see Partial Custom Tabs.
- For details on feature compatibility, see Browser support.
- iOS (15.0+): Supports displaying as a bottom sheet with standard system presentation options.
import 'package:flutter/material.dart';
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
Future<void> _launchUrlInSheetView(BuildContext context) async {
final theme = Theme.of(context);
final mediaQuery = MediaQuery.of(context);
await launchUrl(
Uri.parse('https://flutter.dev'),
customTabsOptions: CustomTabsOptions.partial(
configuration: PartialCustomTabsConfiguration.adaptiveSheet(
initialHeight: mediaQuery.size.height * 0.7,
initialWidth: mediaQuery.size.width * 0.4,
activitySideSheetMaximizationEnabled: true,
activitySideSheetDecorationType:
CustomTabsActivitySideSheetDecorationType.shadow,
activitySideSheetRoundedCornersPosition:
CustomTabsActivitySideSheetRoundedCornersPosition.top,
cornerRadius: 16,
),
colorSchemes: CustomTabsColorSchemes.defaults(
toolbarColor: theme.colorScheme.surface,
),
),
safariVCOptions: SafariViewControllerOptions.pageSheet(
configuration: const SheetPresentationControllerConfiguration(
detents: {
SheetPresentationControllerDetent.large,
SheetPresentationControllerDetent.medium,
},
prefersScrollingExpandsWhenScrolledToEdge: true,
prefersGrabberVisible: true,
prefersEdgeAttachedInCompactHeight: true,
),
preferredBarTintColor: theme.colorScheme.surface,
preferredControlTintColor: theme.colorScheme.onSurface,
dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,
),
);
}
Close the Custom Tabs
You can manually close the Custom Tabs.
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
Future<void> _closeCustomTabsManually() async {
await closeCustomTabs();
}
Performance optimization
To enhance performance when launching URLs, especially on mobile platforms,
you can utilize the following functions. These functions help reduce startup time and provide a smoother user experience.
For more details, please refer to the example app.
Platform-Specific Behaviors
Android
- Pre-Warming the Browser Process: Use
warmupCustomTabs()
to pre-warm the Custom Tabs browser process. This initializes the browser in the background and can reduce the time it takes to launch a URL.
// You can specify `CustomTabsSessionOptions` if you want to customize the browser to be launched.
final customTabsSession = await warmupCustomTabs();
- Pre-Fetching URLs: Use
mayLaunchUrl(s)
to inform the browser about URLs that might be launched. This allows the browser to pre-fetch content, improving load times when the URL is actually opened.
await mayLaunchUrl(
Uri.parse('https://flutter.dev'),
customTabsSession: customTabsSession, // Use the session from warmupCustomTabs()
);
- Launch the URL with Pre-Warmed Session: You can launch a URL with a pre-warmed session to improve the startup performance of the Custom Tabs.
Future<void> _launchUrlWithSession(
BuildContext context,
CustomTabsSession customTabsSession,
) async {
final theme = Theme.of(context);
await launchUrl(
Uri.parse('https://flutter.dev'),
customTabsOptions: CustomTabsOptions(
colorSchemes: CustomTabsColorSchemes.defaults(
toolbarColor: theme.colorScheme.surface,
),
// Use the pre-warmed session.
browser: CustomTabsBrowserConfiguration.session(customTabsSession),
),
);
}
iOS
- Pre-Warming Connections: Starting from iOS 15, you can use
mayLaunchUrl(s)
to pre-warm web connections. This can help reduce the time to load a page by preparing the network resources ahead of time.
final prewarmingSession = await mayLaunchUrl(Uri.parse('https://flutter.dev'));
It's crucial to call invalidateSession
to release resources and properly dispose of the session when it is no longer needed.
await invalidateSession(prewarmingSession);
Android: Prefer the default browser over Chrome
On Android, the plugin defaults to launching Chrome, which supports all Custom Tabs features. You can prioritize launching the default browser on the device that supports Custom Tabs over Chrome.
Note
Some browsers may not support the options specified in CustomTabsOptions
.
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
Future<void> _launchUrlInDefaultBrowserOnAndroid() async {
await launchUrl(
Uri.parse('https://flutter.dev'),
customTabsOptions: CustomTabsOptions(
browser: const CustomTabsBrowserConfiguration(
prefersDefaultBrowser: true,
),
),
);
}
Android: Enable App-specific history
App-specific history improves your users' browsing experience by organizing web pages they've visited through your Flutter app into dedicated groups within Chrome's history.
When enabled, pages opened from your app appear with your app's name in Chrome's history, creating a more organized browsing experience.
Requirements:
- Android 14 and above
- Chrome version 126 and above
For more technical details, see App-specific history.
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
Future<void> _launchUrlWithAppSpecificHistoryOnAndroid() async {
await launchUrl(
Uri.parse('https://flutter.dev'),
customTabsOptions: const CustomTabsOptions(
shareIdentityEnabled: true,
),
);
}