Flutter Templates
Construyendo una aplicación de comercio electrónico con Flutter, Back4App y la integración de Stripe a través del código en la nube
49 min
introducción desarrollar una aplicación de comercio electrónico implica múltiples componentes, incluyendo listados de productos, funcionalidad de carrito de compras, procesamiento de pagos seguro, seguimiento de pedidos y reseñas de usuarios combinar el potente kit de herramientas de ui de flutter con los servicios backend escalables de back4app simplifica el proceso de desarrollo además, integrar stripe para el procesamiento de pagos a través de back4app cloud code permite un manejo de transacciones seguro y profesional en este tutorial, construirás una aplicación de comercio electrónico con las siguientes características listados de productos mostrar productos con imágenes, descripciones y precios carrito de compras agregar y eliminar productos del carrito cuentas de usuario gestionar perfiles y direcciones de usuario pago seguro procesar pagos de manera segura utilizando stripe a través de back4app cloud code seguimiento de pedidos rastrear el estado y la historia de los pedidos reseñas y calificaciones permitir a los usuarios enviar reseñas y calificaciones requisitos previos para seguir este tutorial, necesitarás flutter sdk instalado en tu máquina sigue la guía de instalación de flutter https //flutter dev/docs/get started/install conocimientos básicos de flutter y dart un ide o editor de texto como visual studio code o android studio una cuenta de back4app regístrate en back4app https //www back4app com/ cuenta de stripe regístrate en stripe https //stripe com/ para obtener claves api node js y npm instalados para el desarrollo de cloud code paso 1 – configuración del proyecto flutter 1 1 crear un nuevo proyecto flutter abre tu terminal y ejecuta flutter create ecommerce app navega al directorio del proyecto cd ecommerce app 1 2 agregar dependencias abre pubspec yaml y agrega las siguientes dependencias dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 provider ^6 0 0 cached network image ^3 2 0 flutter stripe ^5 2 0 uuid ^3 0 6 ejecuta flutter pub get para instalar los paquetes nota parse server sdk flutter para la integración de back4app provider para la gestión del estado cached network image para la carga eficiente de imágenes flutter stripe para la integración de stripe en el lado del cliente uuid para generar identificadores únicos paso 2 – configuración de back4app 2 1 crear una nueva aplicación en back4app inicia sesión en tu panel de back4app https //dashboard back4app com/ haz clic en "crear nueva app" ingresa "ecommerceapp" como el nombre de la aplicación y haz clic en "crear" 2 2 configurar los modelos de datos necesitamos crear varias clases en back4app producto usuario (clase incorporada) orden ordenitem reseña 2 2 1 clase producto navegar a la "base de datos" sección haga clic en "crear una clase" seleccione "personalizado" e ingrese "producto" como el nombre de la clase agregue las siguientes columnas nombre cadena descripción cadena precio número imagen archivo categoría cadena inventario número 2 2 2 clase de pedido cree una "clase de pedido" con las siguientes columnas usuario puntero< usuario> totalcantidad número estado cadena (valores "pendiente", "pagado", "enviado", "entregado") paymentintentid cadena (para rastrear el pago de stripe) direccióndeenvio cadena 2 2 3 clase de item de pedido crea un "orderitem" clase con las siguientes columnas orden puntero producto puntero cantidad número precio número 2 2 4 clase de reseña crea una "review" clase con las siguientes columnas producto puntero usuario puntero< usuario> calificación número comentario cadena 2 3 obtener credenciales de la aplicación navegar a configuración de la aplicación > seguridad y claves anote su id de aplicación y clave de cliente paso 3 – implementación de la gestión de productos 3 1 inicializando parse en flutter abrir lib/main dart y modificarlo import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ provider/provider dart'; import 'screens/home screen dart'; import 'services/product service dart'; void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, ); runapp(myapp()); } class myapp extends statelesswidget { @override widget build(buildcontext context) { return changenotifierprovider\<productservice>( create ( ) => productservice(), child materialapp( title 'e commerce app', theme themedata( primaryswatch colors blue, ), home homescreen(), ), ); } } reemplace 'your application id' y 'your client key' con sus credenciales de back4app 3 2 creando el modelo de producto crea un directorio models bajo lib y añade product dart // lib/models/product dart class product { string id; string name; string description; double price; string imageurl; string category; int inventory; product({ required this id, required this name, required this description, required this price, required this imageurl, required this category, required this inventory, }); } 3 3 implementando el servicio de producto crea un directorio services bajo lib y añade product service dart // lib/services/product service dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/product dart'; class productservice with changenotifier { list\<product> products = \[]; future\<void> fetchproducts() async { final query = querybuilder\<parseobject>(parseobject('product')); final response = await query query(); if (response success && response results != null) { products = response results! map((data) { return product( id data objectid!, name data get\<string>('name')!, description data get\<string>('description')!, price data get\<num>('price')! todouble(), imageurl data get\<parsefilebase>('image')! url!, category data get\<string>('category')!, inventory data get\<num>('inventory')! toint(), ); }) tolist(); notifylisteners(); } } } 3 4 creando la pantalla de inicio crea screens directorio bajo lib y añade home screen dart // lib/screens/home screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/product service dart'; import 'product detail screen dart'; class homescreen extends statefulwidget { @override homescreenstate createstate() => homescreenstate(); } class homescreenstate extends state\<homescreen> { late productservice productservice; @override void initstate() { super initstate(); productservice = provider of\<productservice>(context, listen false); productservice fetchproducts(); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('e commerce app'), actions \[ iconbutton( icon icon(icons shopping cart), onpressed () { // navigate to cart screen (to be implemented) }, ), ], ), body consumer\<productservice>( builder (context, productservice, child) { if (productservice products isempty) { return center(child circularprogressindicator()); } return gridview\ builder( padding edgeinsets all(8 0), itemcount productservice products length, griddelegate slivergriddelegatewithfixedcrossaxiscount( crossaxiscount 2, childaspectratio 0 75, ), itembuilder (context, index) { final product = productservice products\[index]; return gesturedetector( ontap () { navigator push( context, materialpageroute( builder ( ) => productdetailscreen(product product), ), ); }, child card( child column( children \[ expanded( child image network( product imageurl, fit boxfit cover, ), ), text(product name), text('\\$${product price tostringasfixed(2)}'), ], ), ), ); }, ); }, ), ); } } 3 5 pantalla de detalle del producto crear product detail screen dart bajo lib/screens/ // lib/screens/product detail screen dart import 'package\ flutter/material dart'; import ' /models/product dart'; import ' /services/cart service dart'; import 'package\ provider/provider dart'; class productdetailscreen extends statelesswidget { final product product; productdetailscreen({required this product}); @override widget build(buildcontext context) { final cartservice = provider of\<cartservice>(context); return scaffold( appbar appbar(title text(product name)), body column( children \[ expanded(child image network(product imageurl)), padding( padding const edgeinsets all(16 0), child text(product description), ), text('\\$${product price tostringasfixed(2)}'), elevatedbutton( onpressed () { cartservice addtocart(product); scaffoldmessenger of(context) showsnackbar( snackbar(content text('added to cart')), ); }, child text('add to cart'), ), ], ), ); } } paso 4 – implementación de cuentas de usuario 4 1 servicio de autenticación agregar auth service dart bajo lib/services/ // lib/services/auth service dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; class authservice with changenotifier { parseuser? user; future\<bool> signup(string username, string password, string email) async { user = parseuser createuser(username, password, email); final response = await user! signup(); if (response success) { notifylisteners(); return true; } else { user = null; return false; } } future\<bool> login(string username, string password) async { user = parseuser(username, password, null); final response = await user! login(); if (response success) { notifylisteners(); return true; } else { user = null; return false; } } future\<void> logout() async { if (user != null) { await user! logout(); user = null; notifylisteners(); } } bool get isauthenticated => user != null; } 4 2 pantallas de autenticación crear login screen dart y signup screen dart bajo lib/screens/ pantalla de inicio de sesión // lib/screens/login screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import 'home screen dart'; import 'signup screen dart'; class loginscreen extends statelesswidget { final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void login(buildcontext context) async { final authservice = provider of\<authservice>(context, listen false); bool success = await authservice login( usernamecontroller text trim(), passwordcontroller text trim(), ); if (success) { navigator pushreplacement( context, materialpageroute(builder ( ) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('login failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('e commerce app login'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username or email'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => login(context), child text('login'), ), textbutton( onpressed () { navigator push( context, materialpageroute(builder ( ) => signupscreen()), ); }, child text('don\\'t have an account? sign up'), ) ], ), ), ); } } pantalla de registro // lib/screens/signup screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import 'home screen dart'; class signupscreen extends statelesswidget { final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller emailcontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void signup(buildcontext context) async { final authservice = provider of\<authservice>(context, listen false); bool success = await authservice signup( usernamecontroller text trim(), passwordcontroller text trim(), emailcontroller text trim(), ); if (success) { navigator pushreplacement( context, materialpageroute(builder ( ) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('signup failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('e commerce app signup'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), textfield( controller emailcontroller, decoration inputdecoration(labeltext 'email'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => signup(context), child text('sign up'), ), ], ), ), ); } } 4 3 actualizar main para incluir authservice en main dart , envuelve el materialapp con multiprovider // in main dart class myapp extends statelesswidget { @override widget build(buildcontext context) { return multiprovider( providers \[ changenotifierprovider\<productservice>( create ( ) => productservice(), ), changenotifierprovider\<authservice>( create ( ) => authservice(), ), changenotifierprovider\<cartservice>( create ( ) => cartservice(), ), ], child materialapp( // ), ); } } 4 4 redirección basada en el estado de autenticación modifica main dart para verificar el estado de autenticación // main dart // inside the build method home consumer\<authservice>( builder (context, authservice, child) { if (authservice isauthenticated) { return homescreen(); } else { return loginscreen(); } }, ), paso 5 – funcionalidad del carrito de compras 5 1 crear servicio de carrito agregar cart service dart bajo lib/services/ // lib/services/cart service dart import 'package\ flutter/material dart'; import ' /models/product dart'; class cartitem { final product product; int quantity; cartitem({required this product, this quantity = 1}); } class cartservice with changenotifier { map\<string, cartitem> items = {}; void addtocart(product product) { if ( items containskey(product id)) { items\[product id]! quantity++; } else { items\[product id] = cartitem(product product); } notifylisteners(); } void removefromcart(string productid) { items remove(productid); notifylisteners(); } void clearcart() { items clear(); notifylisteners(); } map\<string, cartitem> get items => items; double get totalamount { double total = 0 0; items foreach((key, cartitem) { total += cartitem product price cartitem quantity; }); return total; } } 5 2 crear pantalla de carrito agregar cart screen dart bajo lib/screens/ // lib/screens/cart screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/cart service dart'; import 'checkout screen dart'; class cartscreen extends statelesswidget { @override widget build(buildcontext context) { final cartservice = provider of\<cartservice>(context); final cartitems = cartservice items values tolist(); return scaffold( appbar appbar(title text('your cart')), body column( children \[ expanded( child listview\ builder( itemcount cartservice items length, itembuilder (context, index) { final cartitem = cartitems\[index]; return listtile( leading image network(cartitem product imageurl), title text(cartitem product name), subtitle text('quantity ${cartitem quantity}'), trailing text('\\$${(cartitem product price cartitem quantity) tostringasfixed(2)}'), ); }, ), ), text('total \\$${cartservice totalamount tostringasfixed(2)}'), elevatedbutton( onpressed () { navigator push( context, materialpageroute(builder ( ) => checkoutscreen()), ); }, child text('proceed to checkout'), ), ], ), ); } } paso 6 – pago seguro con integración de stripe a través de cloud code 6 1 configurar cuenta de stripe regístrate para una cuenta de stripe https //dashboard stripe com/register obtén tu clave publicable y clave secreta desde el panel de control de stripe en desarrolladores > claves api 6 2 instalar sdk de stripe en cloud code back4app admite funciones de cloud code escritas en javascript escribiremos funciones de cloud code para manejar el procesamiento de pagos 6 2 1 crear proyecto de cloud code en el panel de control de tu aplicación back4app, ve a configuración de la aplicación > funciones de cloud code haz clic en "editar código" para abrir el editor de cloud code 6 2 2 inicializar npm e instalar paquete de stripe en la terminal de cloud code (proporcionada en el editor), ejecuta npm init y npm install stripe\@8 174 0 nota el cloud code de back4app utiliza la versión 14 x de node js, así que asegúrate de la compatibilidad 6 3 crear función en la nube para el intento de pago crea o modifica main js en el editor de cloud code // main js const stripe = require('stripe'); const stripe = stripe('your stripe secret key'); parse cloud define('createpaymentintent', async (request) => { const { amount, currency } = request params; try { const paymentintent = await stripe paymentintents create({ amount amount, currency currency, }); return { clientsecret paymentintent client secret }; } catch (error) { throw new parse error(500, error message); } }); reemplaza 'your stripe secret key' con tu clave secreta de stripe real nota de seguridad nunca expongas tu clave secreta en el lado del cliente mantenla segura en el cloud code 6 4 desplegar cloud code haz clic en "desplegar" en el editor de cloud code para desplegar tus funciones 6 5 implementar pago en flutter 6 5 1 inicializar stripe en flutter en main dart , después de parse() initialize , añade import 'package\ flutter stripe/flutter stripe dart'; // inside main() async stripe publishablekey = 'your stripe publishable key'; reemplaza 'tu clave publicable de stripe' con tu clave publicable de stripe 6 5 2 crear pantalla de checkout añade checkout screen dart bajo lib/screens/ // lib/screens/checkout screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/cart service dart'; import 'package\ flutter stripe/flutter stripe dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'order confirmation screen dart'; class checkoutscreen extends statelesswidget { future\<void> processpayment(buildcontext context) async { final cartservice = provider of\<cartservice>(context, listen false); final totalamount = (cartservice totalamount 100) toint(); // amount in cents // call cloud function to create payment intent final response = await parsecloudfunction('createpaymentintent') execute( parameters { 'amount' totalamount, 'currency' 'usd', }, ); if (response success) { final clientsecret = response result\['clientsecret']; // initialize payment sheet await stripe instance initpaymentsheet( paymentsheetparameters setuppaymentsheetparameters( paymentintentclientsecret clientsecret, merchantdisplayname 'your e commerce app', ), ); // display payment sheet await stripe instance presentpaymentsheet(); // payment successful // save order to back4app (to be implemented) cartservice clearcart(); navigator pushreplacement( context, materialpageroute(builder ( ) => orderconfirmationscreen()), ); } else { scaffoldmessenger of(context) showsnackbar( snackbar(content text('payment failed ${response error! message}')), ); } } @override widget build(buildcontext context) { final cartservice = provider of\<cartservice>(context); return scaffold( appbar appbar(title text('checkout')), body column( children \[ text('total \\$${cartservice totalamount tostringasfixed(2)}'), elevatedbutton( onpressed () => processpayment(context), child text('pay now'), ), ], ), ); } } 6 5 3 manejar la confirmación de pago crear order confirmation screen dart bajo lib/screens/ // lib/screens/order confirmation screen dart import 'package\ flutter/material dart'; class orderconfirmationscreen extends statelesswidget { @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('order confirmed'), automaticallyimplyleading false, ), body center( child text('thank you for your purchase!'), ), ); } } 6 6 guardando la orden en back4app modifica el processpayment método para guardar los detalles de la orden // after successful payment final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; // create order object final order = parseobject('order') set('user', user) set('totalamount', cartservice totalamount) set('status', 'paid') set('paymentintentid', clientsecret); // save order final orderresponse = await order save(); if (orderresponse success) { final orderobject = orderresponse result; // save orderitems for (var cartitem in cartservice items values) { final orderitem = parseobject('orderitem') set('order', orderobject) set('product', parseobject('product') objectid = cartitem product id) set('quantity', cartitem quantity) set('price', cartitem product price); await orderitem save(); } // clear cart and navigate cartservice clearcart(); navigator pushreplacement( context, materialpageroute(builder ( ) => orderconfirmationscreen()), ); } else { scaffoldmessenger of(context) showsnackbar( snackbar(content text('failed to save order')), ); } paso 7 – seguimiento de orden 7 1 crear servicio de orden agregar order service dart bajo lib/services/ // lib/services/order service dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/order dart'; class orderservice with changenotifier { list\<order> orders = \[]; future\<void> fetchorders(parseuser user) async { final query = querybuilder\<parseobject>(parseobject('order')) whereequalto('user', user) orderbydescending('createdat'); final response = await query query(); if (response success && response results != null) { orders = response results! map((data) { return order fromparseobject(data); }) tolist(); notifylisteners(); } } } paso 7 – seguimiento de orden 7 2 crear modelo de pedido agregar order dart bajo lib/models/ // lib/models/order dart import 'package\ parse server sdk flutter/parse server sdk dart'; class order { string id; double totalamount; string status; datetime createdat; order({ required this id, required this totalamount, required this status, required this createdat, }); factory order fromparseobject(parseobject object) { return order( id object objectid!, totalamount object get\<num>('totalamount')! todouble(), status object get\<string>('status')!, createdat object createdat!, ); } } 7 3 crear pantalla de pedidos agregar orders screen dart bajo lib/screens/ // lib/screens/orders screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/order service dart'; import ' /services/auth service dart'; import ' /models/order dart'; class ordersscreen extends statefulwidget { @override ordersscreenstate createstate() => ordersscreenstate(); } class ordersscreenstate extends state\<ordersscreen> { late orderservice orderservice; @override void initstate() { super initstate(); orderservice = provider of\<orderservice>(context, listen false); final authservice = provider of\<authservice>(context, listen false); orderservice fetchorders(authservice user!); } @override widget build(buildcontext context) { return scaffold( appbar appbar(title text('your orders')), body consumer\<orderservice>( builder (context, orderservice, child) { if (orderservice orders isempty) { return center(child text('no orders found ')); } return listview\ builder( itemcount orderservice orders length, itembuilder (context, index) { final order = orderservice orders\[index]; return listtile( title text('order #${order id}'), subtitle text('status ${order status}'), trailing text('\\$${order totalamount tostringasfixed(2)}'), ); }, ); }, ), ); } } paso 8 – reseñas y calificaciones 8 1 crear servicio de reseñas agregar review service dart bajo lib/services/ // lib/services/review service dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/review\ dart'; class reviewservice with changenotifier { list\<review> reviews = \[]; future\<void> fetchreviews(string productid) async { final query = querybuilder\<parseobject>(parseobject('review')) whereequalto('product', parseobject('product') objectid = productid) includeobject(\['user']); final response = await query query(); if (response success && response results != null) { reviews = response results! map((data) { return review\ fromparseobject(data); }) tolist(); notifylisteners(); } } future\<void> submitreview(string productid, parseuser user, int rating, string comment) async { final review = parseobject('review') set('product', parseobject('product') objectid = productid) set('user', user) set('rating', rating) set('comment', comment); await review\ save(); await fetchreviews(productid); } } 8 2 crear modelo de reseña agregar review\ dart bajo lib/models/ // lib/models/review\ dart import 'package\ parse server sdk flutter/parse server sdk dart'; class review { string id; int rating; string comment; parseuser user; review({ required this id, required this rating, required this comment, required this user, }); factory review\ fromparseobject(parseobject object) { return review( id object objectid!, rating object get\<num>('rating')! toint(), comment object get\<string>('comment')!, user object get\<parseuser>('user')!, ); } } 8 3 actualizar la pantalla de detalles del producto en product detail screen dart , agrega una sección para mostrar y enviar reseñas // at the end of the column in productdetailscreen expanded( child column( children \[ // display reviews expanded( child consumer\<reviewservice>( builder (context, reviewservice, child) { if (reviewservice reviews isempty) { return center(child text('no reviews yet ')); } return listview\ builder( itemcount reviewservice reviews length, itembuilder (context, index) { final review = reviewservice reviews\[index]; return listtile( title text(review\ user username ?? 'anonymous'), subtitle text(review\ comment), trailing text('${review\ rating}/5'), ); }, ); }, ), ), // submit review textfield( controller reviewcontroller, decoration inputdecoration(hinttext 'write a review'), ), row( children \[ text('rating '), dropdownbutton\<int>( value rating, onchanged (value) { setstate(() { rating = value!; }); }, items list generate(5, (index) => index + 1) map((e) => dropdownmenuitem(value e, child text('$e'))) tolist(), ), elevatedbutton( onpressed () { final authservice = provider of\<authservice>(context, listen false); reviewservice submitreview( product id, authservice user!, rating, reviewcontroller text trim(), ); reviewcontroller clear(); }, child text('submit'), ), ], ), ], ), ), conclusión en este tutorial completo, has construido una aplicación de comercio electrónico utilizando flutter y back4app, integrada con stripe para el procesamiento seguro de pagos a través de cloud code implementaste características clave como listados de productos, funcionalidad de carrito de compras, autenticación de usuarios, seguimiento de pedidos y reseñas puntos clave integración de back4app simplifica la gestión del backend para tu aplicación flutter integración de stripe a través de cloud code procesa pagos de forma segura sin exponer claves sensibles arquitectura modular separar servicios y modelos mejora la mantenibilidad próximos pasos mejorar la seguridad implementar un manejo adecuado de errores y validación de entradas mejoras de ui/ux refinar la interfaz de usuario para una mejor experiencia del usuario gestión de inventario actualizar el inventario de productos al realizar una compra notificaciones por correo electrónico enviar correos electrónicos de confirmación de pedidos a los usuarios panel de administración crear una interfaz de administración para gestionar productos y pedidos recursos adicionales documentación de back4app https //www back4app com/docs guía de parse server https //docs parseplatform org/ documentación oficial de flutter https //flutter dev/docs referencia de api de stripe https //stripe com/docs/api paquete de flutter stripe https //pub dev/packages/flutter stripe ¡feliz codificación!