tutoriales.com

Flutter: Integración de Pagos con Stripe para E-commerce Móvil

Este tutorial te guiará paso a paso en la integración de Stripe para procesar pagos en tus aplicaciones Flutter. Cubriremos la configuración del entorno, la implementación del backend (Node.js) para la creación de intenciones de pago y la interfaz de usuario en Flutter para una experiencia de compra fluida y segura. Ideal para desarrolladores que buscan añadir funcionalidades de e-commerce.

Intermedio15 min de lectura5 views
Reportar error

🎯 Introducción a la Integración de Pagos con Stripe en Flutter

En el mundo del desarrollo móvil, la capacidad de procesar pagos de forma segura y eficiente es crucial para muchas aplicaciones, especialmente las de e-commerce. Stripe es una de las plataformas de pago más populares y robustas, ofreciendo una API flexible y herramientas fáciles de usar para desarrolladores.

Este tutorial te proporcionará una guía completa para integrar Stripe en tu aplicación Flutter, abarcando tanto el lado del cliente (Flutter) como un pequeño backend (Node.js) necesario para manejar la lógica de negocio y las operaciones sensibles.

🔥 Importante: La seguridad es primordial. Nunca manejes claves secretas de Stripe o realices operaciones de pago sensibles directamente desde tu aplicación cliente. Siempre debes usar un backend seguro para estas tareas.

¿Por qué Stripe y Flutter?

Stripe destaca por su facilidad de integración, seguridad robusta y soporte para múltiples métodos de pago. Flutter, por su parte, permite construir interfaces de usuario hermosas y de alto rendimiento para iOS, Android y la web desde una única base de código. La combinación de ambos es ideal para crear aplicaciones de e-commerce móviles modernas y eficientes.

Requisitos Previos

Antes de empezar, asegúrate de tener lo siguiente:

  • Flutter SDK instalado y configurado.
  • Node.js y npm/yarn instalados para el backend.
  • Una cuenta de Stripe (puedes usar el modo de prueba).
  • Conocimientos básicos de Flutter y JavaScript/Node.js.
  • Un entorno de desarrollo (VS Code, Android Studio, etc.).

🛠️ Configuración Inicial: Backend y Dependencias

Comenzaremos configurando nuestro entorno de desarrollo y las dependencias necesarias tanto para el backend como para el frontend de Flutter.

1. Configuración de la Cuenta de Stripe

Si aún no tienes una cuenta de Stripe, regístrate en stripe.com. Una vez dentro, ve al Dashboard de desarrollador. Necesitaremos dos claves:

  • Clave Publicable (Publishable key): pk_test_... (para el frontend).
  • Clave Secreta (Secret key): sk_test_... (para el backend).
⚠️ Advertencia: Guarda tu clave secreta de forma segura y nunca la expongas en el código de tu aplicación cliente.

2. Configuración del Backend (Node.js con Express)

Crearemos un servidor Node.js simple que manejará las llamadas a la API de Stripe. Este servidor será responsable de crear las PaymentIntent y manejar los webhooks (opcional para este tutorial, pero recomendado para escenarios reales).

2.1. Crear el Proyecto Backend

Crea una nueva carpeta para tu backend y inicializa un proyecto Node.js:

mkdir stripe_backend
cd stripe_backend
npm init -y

2.2. Instalar Dependencias del Backend

Instala express, stripe y dotenv (para manejar variables de entorno):

npm install express stripe dotenv cors

cors es útil para permitir solicitudes desde tu aplicación Flutter durante el desarrollo.

2.3. Crear el Archivo .env

Crea un archivo .env en la raíz de tu carpeta stripe_backend y añade tu clave secreta de Stripe. También puedes definir el puerto del servidor:

STRIPE_SECRET_KEY=sk_test_YOUR_SECRET_KEY
PORT=3000

Reemplaza sk_test_YOUR_SECRET_KEY con tu clave secreta real.

2.4. Código del Servidor index.js

Crea un archivo index.js en la raíz de stripe_backend con el siguiente contenido:

require('dotenv').config();
const express = require('express');
const Stripe = require('stripe');
const cors = require('cors');

const app = express();
const port = process.env.PORT || 3000;
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);

app.use(express.json());
app.use(cors()); // Permite todas las solicitudes CORS, ajustar en producción

app.get('/', (req, res) => {
  res.send('Stripe Backend is running!');
});

app.post('/create-payment-intent', async (req, res) => {
  const { amount, currency } = req.body;

  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: amount, // en céntimos
      currency: currency,
      payment_method_types: ['card'],
    });
    res.json({ clientSecret: paymentIntent.client_secret });
  } catch (e) {
    res.status(400).json({ error: e.message });
  }
});

app.listen(port, () => {
  console.log(`Stripe Backend listening at http://localhost:${port}`);
});

Este backend simple expone un endpoint /create-payment-intent que recibe un amount y currency y devuelve el clientSecret necesario para completar el pago desde el frontend.

2.5. Iniciar el Servidor Backend

Ejecuta tu servidor Node.js:

node index.js

You should see Stripe Backend listening at http://localhost:3000 in your console.

3. Configuración de Flutter Frontend

Ahora, configura tu aplicación Flutter para interactuar con Stripe.

3.1. Crear un Nuevo Proyecto Flutter (Si es necesario)

flutter create stripe_ecommerce_app
cd stripe_ecommerce_app

3.2. Instalar Dependencias de Flutter

Necesitaremos el paquete flutter_stripe para interactuar con la API de Stripe desde Flutter y http para hacer llamadas a nuestro backend.

flutter pub add flutter_stripe http

3.3. Configurar flutter_stripe

En tu archivo main.dart, inicializa flutter_stripe con tu clave publicable de Stripe.

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:stripe_ecommerce_app/home_page.dart'; // Crearemos esto después

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Inicializa Stripe con tu clave publicable
  Stripe.publishableKey = 'pk_test_YOUR_PUBLISHABLE_KEY';

  await Stripe.instance.applySettings();

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stripe E-commerce App',
      theme: ThemeData(primarySwatch: Colors.blueGrey),
      home: const HomePage(),
    );
  }
}

Reemplaza pk_test_YOUR_PUBLISHABLE_KEY con tu clave publicable real de Stripe.

💳 Implementación del Frontend: Interfaz de Pago

Ahora construiremos la interfaz de usuario en Flutter para que el usuario pueda ingresar los detalles de su tarjeta y realizar el pago.

1. Crear la Página Principal (home_page.dart)

Esta página simulará un carrito de compras y un botón para proceder al pago.

// home_page.dart
import 'package:flutter/material.dart';
import 'package:stripe_ecommerce_app/payment_service.dart'; // Crearemos esto después

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Mi Tienda Flutter')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text(
                'Producto de Ejemplo',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 10),
              const Text(
                'Precio: 99.99 EUR',
                style: TextStyle(fontSize: 18),
              ),
              const SizedBox(height: 30),
              ElevatedButton(
                onPressed: () async {
                  await _makePayment(context);
                },
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
                ),
                child: const Text(
                  'Pagar Ahora',
                  style: TextStyle(fontSize: 20),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _makePayment(BuildContext context) async {
    // Aquí llamaremos al servicio de pago
    try {
      await PaymentService().makePayment(amount: '9999', currency: 'EUR'); // Monto en céntimos
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Pago exitoso!')), 
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error al procesar el pago: $e')), 
      );
    }
  }
}

2. Crear el Servicio de Pago (payment_service.dart)

Este servicio encapsulará la lógica para interactuar con nuestro backend y con la API de Stripe.

// payment_service.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;

class PaymentService {
  final String backendUrl = 'http://localhost:3000'; // Asegúrate de que tu backend esté corriendo

  Future<void> makePayment({required String amount, required String currency}) async {
    try {
      // 1. Obtener el clientSecret de nuestro backend
      final response = await http.post(
        Uri.parse('$backendUrl/create-payment-intent'),
        headers: {'Content-Type': 'application/json'},
        body: json.encode({
          'amount': amount,
          'currency': currency,
        }),
      );

      final jsonResponse = json.decode(response.body);
      final clientSecret = jsonResponse['clientSecret'];

      if (clientSecret == null) {
        throw Exception('Error al obtener clientSecret del backend.');
      }

      // 2. Inicializar el Payment Sheet de Stripe
      await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
          paymentIntentClientSecret: clientSecret,
          merchantDisplayName: 'Mi Tienda Flutter',
          currencyCode: currency,
          style: ThemeMode.light, // o ThemeMode.dark
        ),
      );

      // 3. Mostrar el Payment Sheet
      await Stripe.instance.presentPaymentSheet();

      // Si el pago es exitoso, no se lanza ninguna excepción.
      print('Pago realizado exitosamente!');

    } on StripeException catch (e) {
      if (e.error.code == 'Canceled') {
        throw Exception('El usuario canceló el pago.');
      } else {
        throw Exception('Error de Stripe: ${e.error.message}');
      }
    } catch (e) {
      throw Exception('Error inesperado durante el pago: $e');
    }
  }
}
📌 Nota: Para probar en un dispositivo físico, `localhost` no funcionará. Necesitarás reemplazar `http://localhost:3000` por la IP local de tu máquina donde corre el backend (ej. `http://192.168.1.XX:3000`) o desplegar tu backend en un servidor accesible.

🚀 Probando la Integración

Con el backend y el frontend configurados, es hora de probar nuestra integración de pagos.

Paso 1: Asegúrate de que tu servidor Node.js esté ejecutándose (`node index.js`).
Paso 2: Ejecuta tu aplicación Flutter en un emulador o dispositivo (`flutter run`).
Paso 3: En la aplicación Flutter, haz clic en el botón "Pagar Ahora".
Paso 4: Debería aparecer la hoja de pago de Stripe.
Paso 5: Ingresa los detalles de una tarjeta de prueba de Stripe.
Paso 6: Confirma el pago.

Tarjetas de Prueba de Stripe

Stripe proporciona números de tarjeta de prueba para simular diferentes escenarios de pago:

Tipo de TarjetaNúmero de TarjetaFecha de ExpiraciónCVCCódigo Postal
---------------
Visa4242 4242 4242 424212/2412312345
MasterCard5100 0000 0000 000012/2412312345
---------------
American Express3700 0000 0000 00012/24123412345
Fallo4242 4242 4242 4242 (con CVC 000)Cualquier000Cualquier
💡 Consejo: Puedes encontrar una lista más completa y actualizada de tarjetas de prueba en la documentación oficial de Stripe.
1. Cliente Flutter solicita PaymentIntent a Backend 2. Backend (Node.js) llama API Stripe para crear PaymentIntent 3. Stripe API devuelve clientSecret a Backend 4. Backend envía clientSecret a Cliente Flutter 5. Cliente Flutter usa clientSecret para mostrar Payment Sheet 6. Usuario ingresa datos de tarjeta en Payment Sheet 7. Stripe Payment Sheet procesa el pago 8. Stripe Sheet notifica resultado a Flutter

✨ Consideraciones Adicionales y Mejores Prácticas

La integración básica que hemos cubierto es un excelente punto de partida, pero para una aplicación de producción, hay varios aspectos importantes a considerar.

Webhooks de Stripe

Los webhooks son cruciales para recibir notificaciones asíncronas sobre el estado de los pagos. Por ejemplo, si un pago requiere autenticación 3D Secure, el estado del PaymentIntent puede cambiar a requires_action y luego a succeeded una vez que el usuario completa la autenticación. Tu backend debería escuchar estos webhooks para actualizar el estado del pedido en tu base de datos.

// Ejemplo básico de webhook en Node.js (añadir a index.js)
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];

  let event;

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Manejar el evento
  switch (event.type) {
    case 'payment_intent.succeeded':
      const paymentIntentSucceeded = event.data.object;
      // Actualizar tu base de datos: el pago se realizó con éxito
      console.log(`PaymentIntent for ${paymentIntentSucceeded.amount} was successful!`);
      break;
    case 'payment_intent.payment_failed':
      const paymentIntentFailed = event.data.object;
      // Actualizar tu base de datos: el pago falló
      console.log(`PaymentIntent for ${paymentIntentFailed.amount} failed!`);
      break;
    // ... manejar otros tipos de eventos relevantes
    default:
      console.log(`Unhandled event type ${event.type}`);
  }

  res.json({received: true});
});

Para probar webhooks en desarrollo, puedes usar la CLI de Stripe: stripe listen --forward-to localhost:3000/webhook.

Gestión de Errores y Experiencia de Usuario

Es vital ofrecer retroalimentación clara al usuario en caso de errores. Nuestro PaymentService ya maneja algunas excepciones, pero puedes expandirlo para mostrar mensajes más específicos y amigables.

💡 Consejo: Considera implementar un indicador de carga (`CircularProgressIndicator`) mientras se procesa el pago para mejorar la experiencia del usuario y evitar interacciones duplicadas.

Almacenamiento de Métodos de Pago

Para usuarios recurrentes, Stripe permite guardar los métodos de pago. Esto requiere:

  1. Crear un Customer en Stripe (en tu backend) asociado al usuario de tu aplicación.
  2. Adjuntar PaymentMethods al Customer.
  3. Usar el PaymentMethod guardado en futuras transacciones.

Esto va más allá del alcance de este tutorial, pero es una característica muy solicitada en apps de e-commerce.

Seguridad y PCI Compliance

Al usar Stripe.js o flutter_stripe con PaymentSheet, gran parte de la carga de PCI compliance recae en Stripe, ya que los datos sensibles de la tarjeta nunca tocan tus servidores. Sin embargo, es fundamental seguir las mejores prácticas de seguridad en tu backend (validación de entradas, uso de HTTPS, protección de claves).

Diferentes Métodos de Pago

Stripe soporta una gran variedad de métodos de pago globales y locales (Apple Pay, Google Pay, SEPA Direct Debit, etc.). flutter_stripe facilita la integración de muchos de ellos. La PaymentSheet de Stripe se adapta automáticamente para mostrar los métodos de pago relevantes según la configuración de tu cuenta y la región del usuario.

¿Qué es un PaymentIntent?Un PaymentIntent es un objeto de la API de Stripe que representa la intención de cobrar dinero a un cliente. Realiza un seguimiento del ciclo de vida de un proceso de pago, desde los intentos iniciales de pago hasta los fallos y los pagos exitosos.
¿Cómo manejar diferentes divisas?Puedes especificar la `currency` al crear el PaymentIntent. Asegúrate de que tu cuenta de Stripe esté configurada para aceptar la divisa deseada. Los montos siempre deben enviarse en la unidad más pequeña de la divisa (ej. céntimos para EUR, USD).

✅ Conclusión

Has llegado al final de este tutorial sobre la integración de pagos con Stripe en Flutter. Hemos cubierto los pasos esenciales para configurar un backend simple, inicializar Stripe en Flutter y construir una interfaz de usuario para procesar pagos de forma segura. Esta base te permitirá expandir tu aplicación con funcionalidades de e-commerce completas.

La integración de sistemas de pago puede parecer intimidante al principio, pero con herramientas como Stripe y Flutter, el proceso se simplifica enormemente, permitiéndote concentrarte en ofrecer una excelente experiencia de usuario.

¡Felicidades por añadir una funcionalidad tan poderosa a tu arsenal de desarrollo móvil!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!