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.
🎯 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.
¿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).
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');
}
}
}
🚀 Probando la Integración
Con el backend y el frontend configurados, es hora de probar nuestra integración de pagos.
Tarjetas de Prueba de Stripe
Stripe proporciona números de tarjeta de prueba para simular diferentes escenarios de pago:
| Tipo de Tarjeta | Número de Tarjeta | Fecha de Expiración | CVC | Código Postal |
|---|---|---|---|---|
| --- | --- | --- | --- | --- |
| Visa | 4242 4242 4242 4242 | 12/24 | 123 | 12345 |
| MasterCard | 5100 0000 0000 0000 | 12/24 | 123 | 12345 |
| --- | --- | --- | --- | --- |
| American Express | 3700 0000 0000 000 | 12/24 | 1234 | 12345 |
| Fallo | 4242 4242 4242 4242 (con CVC 000) | Cualquier | 000 | Cualquier |
✨ 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.
Almacenamiento de Métodos de Pago
Para usuarios recurrentes, Stripe permite guardar los métodos de pago. Esto requiere:
- Crear un
Customeren Stripe (en tu backend) asociado al usuario de tu aplicación. - Adjuntar
PaymentMethodsalCustomer. - Usar el
PaymentMethodguardado 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
- Flutter: Desarrollando un Sistema de Autenticación Completo con Firebase Auth y Providerintermediate20 min
- Flutter: Implementando Temas Oscuros y Claros Dinámicos con Provider y Shared Preferencesintermediate18 min
- Flutter Avanzado: Sincronización de Datos Offline con WorkManager y Hive para Apps Robuadvanced20 min
- Gestión de Estado Reactiva con BLoC en Flutter: Un Tutorial Completointermediate25 min
- Flutter para Principiantes: Construyendo una Lista de Tareas Interactivas y Persistentes con Isar DBbeginner30 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!