# MD for: https://www.mercadopago.com.mx/developers/en/docs/checkout-pro/mobile-integration/flutter.md \# Integrate with Flutter To integrate Mercado Pago's Checkout Pro into a mobile application, you need to display the web payment flow within your app. For this, use Custom Tabs for Android and Safari View Controller for iOS. In this documentation, you will find detailed instructions on how to perform this integration using Flutter and Custom Tabs. We will present the steps for installing the necessary libraries, configuring dependencies, and provide practical examples of how to open web pages using Custom Tabs. > RED\_MESSAGE > > Before integrating Checkout Pro for mobile applications, you need to create a payment preference in your backend. If you haven't done so yet, refer to the documentation on how to \[Create and configure a payment preference\](https://www.mercadopago.com.mx/developers/en/docs/checkout-pro/create-payment-preference). Next, select the operating system and follow the corresponding step-by-step guide. ::::TabsComponent :::TabComponent{title="Android"} In this step, you will install and configure the necessary dependencies to implement \*\*Custom Tabs\*\* in your Flutter project. ## Install the Flutter Custom Tabs dependency To install the \*\*Flutter Custom Tabs\*\* dependency, which allows you to open web pages within a mobile application, run the following command in your project's root directory: \`\`\`terminal or CMD $ flutter pub add flutter\_custom\_tabs \`\`\` This will add the line \`dependencies: flutter\_custom\_tabs: ^2.4.0\` to the package's \`pubspec.yaml\` file. The \`flutter pub get\` command will be executed automatically. To use \*\*Custom Tabs\*\* in your code, import the package in the Dart file where you want to display the checkout: \`\`\`dart import 'package:flutter\_custom\_tabs/flutter\_custom\_tabs.dart'; \`\`\` > For more information, refer to the \[official Flutter Custom Tabs documentation\](https://pub.dev/packages/flutter\_custom\_tabs). ## Implement Flutter Custom Tabs To implement \*\*Custom Tabs\*\* in your Flutter application, follow the example below, which demonstrates how to open Mercado Pago's checkout in an integrated native browser: \`\`\`dart import 'package:flutter/material.dart'; import 'package:flutter\_custom\_tabs/flutter\_custom\_tabs.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: Center( child: TextButton( child: const Text('Show Flutter homepage'), onPressed: () => \_launchURL(context), ), ), ), ); } 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 ), animations: const CustomTabsAnimations( startEnter: 'slide\_up', startExit: 'android:anim/fade\_out', endEnter: 'android:anim/fade\_in', endExit: 'slide\_down', ), ), ); } catch (e) { // An exception is thrown if there is no browser application installed on the Android device. debugPrint(e.toString()); } } } \`\`\` You can customize the appearance of the displayed screen by specifying options for each platform. For this, use the \*\*CustomTabsOption\*\* configuration class, which allows you to define parameters such as colors, animations, and behaviors of the native browser tab. For more details, refer to the \[official documentation\](https://pub.dev/packages/flutter\_custom\_tabs). ::: :::TabComponent{title="iOS"} In this step, you will install and configure the necessary dependencies to implement \*\*Safari View Controller\*\* in your Flutter project. ## Install url\_launcher To open web pages within your iOS application via \*\*Safari View Controller\*\*, install the \`url\_launcher\` dependency using the following command: \`\`\`terminal or CMD $ flutter pub add url\_launcher \`\`\` This will add the line \`dependencies: url\_launcher: ^6.1.14\` to the package's \*\*pubspec.yaml\*\* file. To use \`url\_launcher\` in your code, import the package in the Dart file where you want to display the Checkout: \`\`\`dart import 'package:url\_launcher/url\_launcher.dart'; \`\`\` > For more information, refer to the \[official url\_launcher documentation\](https://pub.dev/packages/url\_launcher). ## Implement Safari View Controller Below is an example of Flutter integration using \*\*Safari View Controller\*\*: \`\`\`dart import 'package:flutter/material.dart'; import 'package:url\_launcher/url\_launcher.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: Center( child: TextButton( child: const Text('Show Flutter homepage'), onPressed: () => \_launchURL(context), ), ), ), ); } void \_launchURL(BuildContext context) async { final Uri url = Uri.parse('https://flutter.dev'); try { await launchUrl( url, mode: LaunchMode.inAppWebView, webViewConfiguration: const WebViewConfiguration( enableJavaScript: true, enableDomStorage: true, ), ); } catch (e) { debugPrint(e.toString()); } } } \`\`\` In the case of iOS, it is necessary to manually close the \*\*Safari View Controller\*\*. For this, you must monitor URL changes from the component responsible for opening the window or from the application's entry point. When a change is detected, simply call the appropriate method to close the \*\*Safari View Controller\*\*. ### Manually close Safari View Controller To manually close the \*\*Safari View Controller\*\*, follow the example below: \`\`\`dart import 'package:flutter/material.dart'; import 'package:url\_launcher/url\_launcher.dart'; import 'package:uni\_links/uni\_links.dart'; class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => \_MyAppState(); } class \_MyAppState extends State { StreamSubscription? \_sub; @override void initState() { super.initState(); \_initDeepLinkListener(); } void \_initDeepLinkListener() { \_sub = uriLinkStream.listen((String? link) { if (link != null && link.contains('myapp://')) { // Close Safari View Controller launchUrl(Uri.parse('about:blank')); } }, onError: (err) { debugPrint('Error: $err'); }); } @override void dispose() { \_sub?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: Center( child: TextButton( child: const Text('Open Browser'), onPressed: () => \_launchURL(context), ), ), ), ); } void \_launchURL(BuildContext context) async { final Uri url = Uri.parse('https://flutter.dev'); try { await launchUrl( url, mode: LaunchMode.inAppWebView, webViewConfiguration: const WebViewConfiguration( enableJavaScript: true, enableDomStorage: true, ), ); } catch (e) { debugPrint(e.toString()); } } } \`\`\` ::: :::: ## Return to the application with Deep Links For the user to be able to return to your application after completing the payment, you will need to configure Deep Links. This allows the user to be automatically redirected to a specific screen in your application when finishing the payment flow or clicking a return button. ### 1\. Configure return URLs in the payment preference When creating the payment preference in your \*backend\*, add the \`back\_urls\` and \`auto\_return\` parameters. For more information, refer to the documentation on how to \[Create and configure a payment preference\](https://www.mercadopago.com.mx/developers/en/docs/checkout-pro/create-payment-preference). \`\`\`json "back\_urls": { "success": "tuapp://success", "failure": "tuapp://failure", "pending": "tuapp://pending" }, "auto\_return": "approved" \`\`\` > WARNING > > Do not use local domains in the \`back\_urls\` value, such as 'localhost/' or '127.0.0.1' with or without a specified port. We recommend using a server with a named domain (DNS) or development IPs to be able to return to the site after payment. Otherwise, the "Something went wrong" message will appear when the purchase process is completed. ### 2\. Configure Deep Links reception and management in Flutter Flutter allows you to manage Deep Links in both Android and iOS. For this, use packages such as \[\`uni\_links\`\](https://pub.dev/packages/uni\_links) or \[\`go\_router\`\](https://pub.dev/packages/go\_router) to detect and manage internal navigation when the application is opened via Deep Link. > WARNING > > Deep Links configuration is a common procedure for all mobile technologies. Refer to the \[official Flutter documentation on Deep Links\](https://docs.flutter.dev/development/ui/navigation/deep-linking), as well as the \[App Links guide for Android\](https://developer.android.com/training/app-links) or \[Universal Links for iOS\](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app), as applicable.