Un ejemplo completo de Flutter que muestra cómo integrar Conekta Checkout Components en múltiples plataformas (Web, iOS, Android, macOS, Windows).
⚠️ Importante: Esta es una implementación de referencia con fines educativos. Debes adaptarla a tus necesidades específicas y requisitos de seguridad.
- ✅ Soporte multiplataforma (Web, iOS, Android, macOS, Windows, Linux)
- ✅ Integración completa con Conekta Checkout Components
- ✅ Tokenización segura de tarjetas
- ✅ Interfaz moderna y profesional
- ✅ Implementaciones específicas por plataforma (iframe para Web, WebView para nativo)
- ✅ Comunicación en tiempo real entre WebView y Flutter
El formulario de checkout es completamente responsivo y funciona perfectamente en todas las plataformas:
- iOS/Android: WebView nativo con rendimiento fluido
- Web: Implementación basada en iframe
- Desktop: Soporte completo para escritorio (macOS, Windows, Linux)
Este ejemplo sigue un patrón condicional por plataforma:
main.dart
↓
conekta_checkout_screen.dart (Selector de plataforma)
↓
├─→ conekta_checkout_web.dart (Web: IFrameElement)
└─→ conekta_checkout_native.dart (Nativo: WebViewController)
↓
assets/conekta_checkout.html (UI de Conekta)
- Flutter SDK (^3.0.0)
- Para iOS: Xcode y CocoaPods
- Para Android: Android Studio y SDK
- Cuenta de Conekta con claves API
# Clonar el repositorio
git clone <url-de-tu-repo>
cd flutter_checkout
# Instalar dependencias
flutter pub get
# Para iOS
cd ios && pod install && cd ..Edita assets/conekta_checkout.html y actualiza la configuración:
const config = {
locale: 'es',
publicKey: 'TU_LLAVE_PUBLICA_DE_CONEKTA', // Obténla de tu dashboard de Conekta
targetIFrame: '#conekta-checkout-container',
checkoutRequestId: 'TU_CHECKOUT_REQUEST_ID', // Generado desde tu backend
};Nota: El
checkoutRequestIddebe generarse en tu backend usando la API de Conekta. Ver Crear un Checkout Request ID más abajo.
# Web
flutter run -d chrome
# Simulador iOS
flutter run -d "iPhone 17 Pro"
# Android
flutter run -d <device-id>
# macOS
flutter run -d macos- Regístrate en Conekta
- Ve a tu Dashboard → Configuración → Claves API
- Copia tu Llave Pública (empieza con
key_) - Usa Llaves de Prueba para desarrollo, Llaves en Vivo para producción
El checkoutRequestId debe generarse desde tu backend. Ejemplo:
// Ejemplo backend (Node.js)
const conekta = require('conekta');
conekta.api_key = 'TU_LLAVE_PRIVADA';
conekta.locale = 'es';
const checkoutData = {
name: 'Demo Checkout',
type: 'Integration',
recurrent: false,
expires_at: Math.floor(Date.now() / 1000) + (60 * 60 * 24), // 24 horas
allowed_payment_methods: ['card'],
needs_shipping_contact: false,
order_template: {
currency: 'MXN',
customer_info: {
name: 'Nombre del Cliente',
email: 'cliente@ejemplo.com',
phone: '+525512345678'
},
line_items: [{
name: 'Nombre del Producto',
unit_price: 10000, // Monto en centavos (100.00 MXN)
quantity: 1
}]
}
};
conekta.Checkout.create(checkoutData, (err, checkout) => {
console.log(checkout.id); // Este es tu checkoutRequestId
});Crea un archivo env.local (opcional, para referencia):
CONEKTA_PUBLIC_KEY=key_xxxxxxxxxxxxxxx
CONEKTA_PRIVATE_KEY=key_xxxxxxxxxxxxxxx # ¡NUNCA expongas esto del lado del cliente!Agrega estas a tu pubspec.yaml:
dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.13.0
assets:
- assets/conekta_checkout.html
- env.local # OpcionalPor qué es necesario: La seguridad del WebView de iOS bloquea scripts externos por defecto.
Solución: Establece el parámetro baseUrl al cargar el HTML:
// lib/conekta_checkout_native.dart
..loadHtmlString(
htmlContent,
baseUrl: 'https://pay.stg.conekta.io/', // ¡Requerido para iOS!
)Sin esto, el script de Conekta no se cargará en iOS.
Agrega permiso de internet en android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />No se necesita configuración adicional. Funciona de inmediato.
lib/
├── main.dart # App principal con UI demo
├── conekta_checkout_screen.dart # Selector de plataforma
├── conekta_checkout_web.dart # Implementación Web (IFrame)
└── conekta_checkout_native.dart # Implementación Nativa (WebView)
assets/
└── conekta_checkout.html # UI y lógica del Checkout de Conekta
ios/ # Archivos específicos de iOS
android/ # Archivos específicos de Android
web/ # Archivos específicos de Web
Usuario llena los datos de la tarjeta en Conekta Checkout
↓
Se dispara el callback onFinalizePayment()
↓
JavaScript envía mensaje a Flutter
├─→ Web: window.parent.postMessage()
└─→ Nativo: window.PaymentSuccess.postMessage()
↓
Flutter recibe mensaje vía JavaScriptChannel
↓
_handlePaymentSuccess() procesa el token de pago
↓
Muestra mensaje de éxito y cierra checkout
Ocurre un error durante el pago
↓
Se dispara el callback onErrorPayment()
↓
JavaScript envía error a Flutter
↓
Flutter muestra mensaje de error
Edita assets/conekta_checkout.html:
const options = {
backgroundMode: 'lightMode', // 'lightMode' | 'darkMode'
colorPrimary: '#667eea', // Color de tu marca
colorText: '#333333',
colorLabel: '#666666',
inputType: 'minimalMode', // 'minimalMode' | 'normalMode'
autoResize: true,
};Modifica el CSS en assets/conekta_checkout.html:
#conekta-checkout-container {
background: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
min-height: 400px;
}Usa estas tarjetas en modo staging/prueba:
| Marca | Número | CVV | Expiración |
|---|---|---|---|
| Visa | 4242 4242 4242 4242 | 123 | Cualquier futuro |
| Mastercard | 5555 5555 5555 4444 | 123 | Cualquier futuro |
| American Express | 3782 822463 10005 | 1234 | Cualquier futuro |
Nombre: Cualquier nombre (ej: "JUAN PEREZ")
- Staging:
https://pay.stg.conekta.io/(usar llaves de prueba) - Producción:
https://pay.conekta.io/(usar llaves en vivo)
Actualiza la URL del script en assets/conekta_checkout.html:
<script
type="module"
crossorigin
src="https://pay.stg.conekta.io/v1.0/js/conekta-checkout.min.js"
></script>Síntoma: El loader permanece visible, el formulario de checkout no aparece
Solución: Asegúrate de establecer baseUrl en lib/conekta_checkout_native.dart:
..loadHtmlString(htmlContent, baseUrl: 'https://pay.stg.conekta.io/')Causas:
- Sin conexión a internet
- URL del script incorrecta
- CORS/CSP bloqueando
Solución:
- Verifica la conectividad de red
- Verifica la URL del script en
assets/conekta_checkout.html - Usa DevTools del navegador para verificar errores
# Abrir Simulator
open -a Simulator
# Listar dispositivos disponibles
xcrun simctl list devices
# Arrancar un dispositivo específico
xcrun simctl boot <DEVICE_ID>
# Ejecutar Flutter
flutter run -d <DEVICE_ID>cd ios
rm -rf Pods Podfile.lock
pod install
cd ..
flutter clean
flutter run- Nunca expongas llaves privadas: Solo usa llaves públicas del lado del cliente
- Genera checkout IDs del lado del servidor: No hardcodees datos sensibles
- Valida en el backend: Siempre verifica los pagos del lado del servidor
- Usa HTTPS: Nunca cargues el checkout sobre HTTP en producción
- Implementa webhooks: Escucha eventos de Conekta para cumplimiento de órdenes
Antes de pasar a producción:
- Reemplazar llaves de prueba con llaves de producción
- Actualizar URL del script a producción:
https://pay.conekta.io/ - Implementar backend para generar checkout request IDs
- Configurar endpoints de webhooks para recibir notificaciones de pago
- Probar en dispositivos reales (iOS y Android)
- Implementar manejo de errores apropiado
- Agregar analytics/monitoreo
- Revisar implementación de seguridad
- Probar con montos de pago reales (empezar con montos pequeños)
- Soporte Conekta: help.conekta.com
- Comunidad Flutter: flutter.dev/community
Esta es una implementación de ejemplo. Siéntete libre de hacer fork y adaptarla a tus necesidades.
Este ejemplo se proporciona tal cual con fines educativos.
Esta es una implementación de referencia. Antes de usar en producción:
- Revisa y adapta a tus requisitos de seguridad
- Implementa validación apropiada en el backend
- Sigue las directrices de cumplimiento PCI DSS
- Prueba exhaustivamente en todas las plataformas objetivo
Construido con ❤️ usando Flutter y Conekta
¿Preguntas? Abre un issue o contacta al soporte de Conekta para consultas específicas sobre pagos.