Flutter Templates
Construyendo una aplicación de chat en tiempo real en Flutter con Back4App
35 min
introducción crear una aplicación de chat implica gestionar datos en tiempo real, autenticación de usuarios, manejo de medios y almacenamiento de datos eficiente en este tutorial, aprenderás a construir una aplicación de chat en tiempo real en flutter que soporte conversaciones uno a uno y en grupo, estados de mensajes y compartición de medios usaremos back4app—un backend como servicio impulsado por parse server—para manejar las funcionalidades del backend al final de este tutorial, tendrás una aplicación de chat completamente funcional con las siguientes características autenticación de usuarios procesos de registro e inicio de sesión seguros mensajería en tiempo real entrega instantánea de mensajes utilizando consultas en vivo presencia de usuarios seguimiento del estado en línea/fuera de línea de los usuarios almacenamiento de medios envío y recepción de imágenes en los chats historial de mensajes persistencia de historiales de chat para los usuarios requisitos previos para seguir este tutorial, necesitarás flutter sdk instalado en tu máquina sigue la guía oficial 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 para obtener una cuenta gratuita en back4app https //www back4app com/ parse server sdk para flutter añadido a tu proyecto descripción general construiremos una aplicación de chat con los siguientes componentes autenticación de usuarios los usuarios pueden registrarse e iniciar sesión lista de contactos mostrar una lista de usuarios con los que chatear pantalla de chat interfaz de mensajería en tiempo real compartición de medios capacidad para enviar y recibir imágenes estado en línea mostrar el estado en línea/fuera de línea de los usuarios paso 1 – configuración del proyecto flutter 1 1 crear un nuevo proyecto flutter abre tu terminal y ejecuta flutter create chat app navega al directorio del proyecto cd chat app 1 2 agregar dependencias abre pubspec yaml y agrega las siguientes dependencias dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 image picker ^0 8 4+3 cached network image ^3 2 0 uuid ^3 0 4 ejecuta flutter pub get para instalar los paquetes parse server sdk flutter interactuar con back4app image picker seleccionar imágenes de la galería o cámara cached network image carga y almacenamiento en caché de imágenes de manera eficiente uuid generar identificadores únicos paso 2 – configurando back4app 2 1 crear una nueva aplicación de back4app inicia sesión en tu panel de back4app https //dashboard back4app com/ haz clic en "crear nueva aplicación" ingresa un nombre para tu aplicación, por ejemplo, "chatapp" , y haz clic en "crear" 2 2 configurar clases y modelo de datos crearemos las siguientes clases usuario (clase predeterminada de parse) almacena información del usuario mensaje almacena mensajes de chat saladechat representa un chat entre usuarios 2 2 1 clase de usuario campos nombre de usuario cadena contraseña cadena correo electrónico cadena estáenlinea booleano avatar archivo (opcional) el usuario clase está integrada; solo necesitamos asegurarnos de que tenga los campos adicionales 2 2 2 clase mensaje campos remitente puntero< usuario> receptor puntero< usuario> idsaladechat cadena contenido cadena imagen archivo (opcional) creadoen fechahora (agregado automáticamente) 2 2 3 clase saladechat campos chatroomid cadena usuarios array de pointer< user> últimomensaje cadena actualizadoen datetime (actualizado automáticamente) 2 3 obtener credenciales de la aplicación navega a configuración de la aplicación > seguridad y claves anota tu id de aplicación y clave de cliente paso 3 – inicializando parse en tu aplicación flutter abre lib/main dart y modifícalo de la siguiente manera import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'screens/login screen dart'; // you'll create this file next 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 materialapp( title 'chat app', theme themedata( primaryswatch colors blue, ), home loginscreen(), ); } } reemplace 'your application id' y 'your client key' con sus credenciales reales de back4app paso 4 – implementación de la autenticación de usuarios 4 1 crear servicio de autenticación cree un nuevo directorio llamado services bajo lib y agregue un archivo llamado auth service dart // lib/services/auth service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class authservice { future\<parseuser?> signup(string username, string email, string password) async { var user = parseuser(username, password, email); var response = await user signup(); if (response success) { return user; } else { return null; } } future\<parseuser?> login(string username, string password) async { var user = parseuser(username, password, null); var response = await user login(); if (response success) { return user; } else { return null; } } future\<void> logout() async { var user = await parseuser currentuser() as parseuser?; await user? logout(); } future\<parseuser?> getcurrentuser() async { return await parseuser currentuser() as parseuser?; } } 4 2 crear pantallas de inicio de sesión y registro crea un nuevo directorio llamado screens bajo lib y añade archivos llamados login screen dart y signup screen dart 4 2 1 pantalla de inicio de sesión // lib/screens/login screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; import 'signup screen dart'; class loginscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void login(buildcontext context) async { var user = await authservice login( usernamecontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('login failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app login'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), 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 (context) => signupscreen())), child text('don\\'t have an account? sign up'), ), ], ), ), ); } } 4 2 2 pantalla de registro // lib/screens/signup screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; class signupscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller emailcontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void signup(buildcontext context) async { var user = await authservice signup( usernamecontroller text trim(), emailcontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('sign up failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app sign up'), ), 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'), ), ], ), ), ); } } paso 5 – implementación de la presencia del usuario 5 1 actualizar el estado en línea del usuario crea un método en authservice para actualizar el estado en línea del usuario // lib/services/auth service dart class authservice { // existing methods future\<void> updateuseronlinestatus(bool isonline) async { var user = await parseuser currentuser() as parseuser?; if (user != null) { user set('isonline', isonline); await user save(); } } } 5 2 establecer el estado en línea al iniciar y cerrar sesión actualiza los métodos de inicio y cierre de sesión // lib/services/auth service dart class authservice { // existing methods future\<parseuser?> login(string username, string password) async { var user = parseuser(username, password, null); var response = await user login(); if (response success) { await updateuseronlinestatus(true); return user; } else { return null; } } future\<void> logout() async { await updateuseronlinestatus(false); var user = await parseuser currentuser() as parseuser?; await user? logout(); } } paso 6 – mostrando la lista de contactos 6 1 crear servicio de usuario crear user service dart bajo services // lib/services/user service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class userservice { future\<list\<parseuser>> getallusers() async { final querybuilder\<parseuser> queryusers = querybuilder\<parseuser>(parseuser forquery()); final parseresponse apiresponse = await queryusers query(); if (apiresponse success && apiresponse results != null) { return apiresponse results as list\<parseuser>; } else { return \[]; } } } 6 2 crear pantalla de inicio // lib/screens/home screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /services/user service dart'; import ' /services/auth service dart'; import 'chat screen dart'; class homescreen extends statefulwidget { @override homescreenstate createstate() => homescreenstate(); } class homescreenstate extends state\<homescreen> { final userservice userservice = userservice(); final authservice authservice = authservice(); list\<parseuser> users = \[]; parseuser? currentuser; @override void initstate() { super initstate(); fetchusers(); getcurrentuser(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); } void fetchusers() async { var allusers = await userservice getallusers(); setstate(() { users = allusers where((user) => user username != currentuser? username) tolist(); }); } void logout(buildcontext context) async { await authservice logout(); navigator pushreplacementnamed(context, '/'); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('contacts'), actions \[ iconbutton(onpressed () => logout(context), icon icon(icons logout)), ], ), body listview\ builder( itemcount users length, itembuilder (context, index) { var user = users\[index]; return listtile( title text(user username ?? ''), subtitle text(user get('isonline') == true ? 'online' 'offline'), ontap () { navigator push( context, materialpageroute(builder (context) => chatscreen(receiver user)), ); }, ); }, ), ); } } paso 7 – implementación de mensajería en tiempo real con consultas en vivo 7 1 configurar el cliente de consulta en vivo agrega la siguiente dependencia en pubspec yaml dependencies flutter sdk flutter parse server sdk flutter git url https //github com/parse community/parse sdk flutter git ref master esto asegura que tengas la última versión con soporte para live query 7 2 inicializar live query en main dart // lib/main dart void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; const livequeryurl = 'wss\ //your app back4app io'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, livequeryurl livequeryurl, ); runapp(myapp()); } este es un texto adicional para demostrar la estructura reemplace 'your app' con el subdominio de su aplicación back4app 7 3 crear pantalla de chat // lib/screens/chat screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ uuid/uuid dart'; import 'package\ image picker/image picker dart'; import ' /services/auth service dart'; import 'package\ cached network image/cached network image dart'; class chatscreen extends statefulwidget { final parseuser receiver; chatscreen({required this receiver}); @override chatscreenstate createstate() => chatscreenstate(); } class chatscreenstate extends state\<chatscreen> { final authservice authservice = authservice(); parseuser? currentuser; list\<parseobject> messages = \[]; string chatroomid = ''; final texteditingcontroller messagecontroller = texteditingcontroller(); late parselivelist\<parseobject> livemessages; @override void initstate() { super initstate(); getcurrentuser(); setupchatroom(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); if (currentuser != null) { setuplivequery(); } } void setupchatroom() { string userid = currentuser! objectid!; string receiverid = widget receiver objectid!; chatroomid = userid compareto(receiverid) > 0 ? '$userid $receiverid' '$receiverid $userid'; } void setuplivequery() { querybuilder\<parseobject> querymessages = querybuilder\<parseobject>(parseobject('message')) whereequalto('chatroomid', chatroomid) orderbyascending('createdat'); livemessages = parselivelist\<parseobject>( querymessages, listeningincludes \['sender'], lazyloading false, ); setstate(() {}); } void sendmessage({string? content, parsefilebase? imagefile}) async { var message = parseobject('message') set('sender', currentuser) set('receiver', widget receiver) set('chatroomid', chatroomid) set('content', content ?? '') set('image', imagefile); await message save(); messagecontroller clear(); } void pickimage() async { final picker = imagepicker(); final pickedfile = await picker pickimage(source imagesource gallery, imagequality 50); if (pickedfile != null) { var file = parsefile(file(pickedfile path)); await file save(); sendmessage(imagefile file); } } @override void dispose() { livemessages dispose(); super dispose(); } @override widget build(buildcontext context) { if (currentuser == null || livemessages == null) { return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body center(child circularprogressindicator()), ); } return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body column( children \[ expanded( child parselivelistwidget\<parseobject>( query livemessages, reverse false, lazyloading false, childbuilder (context, snapshot) { if (snapshot failed) { return text('error ${snapshot error}'); } else if (snapshot hasdata) { var message = snapshot loadeddata!; var sender = message get\<parseuser>('sender')!; var isme = sender objectid == currentuser! objectid; var content = message get\<string>('content') ?? ''; var image = message get\<parsefilebase>('image'); return align( alignment isme ? alignment centerright alignment centerleft, child container( padding edgeinsets all(8), margin edgeinsets all(8), decoration boxdecoration( color isme ? colors blue\[100] colors grey\[300], borderradius borderradius circular(8), ), child column( crossaxisalignment crossaxisalignment start, children \[ if (content isnotempty) text(content), if (image != null) cachednetworkimage( imageurl image url!, placeholder (context, url) => circularprogressindicator(), errorwidget (context, url, error) => icon(icons error), ), ], ), ), ); } else { return container(); } }, ), ), divider(height 1), container( padding edgeinsets symmetric(horizontal 8), color colors white, child row( children \[ iconbutton( icon icon(icons photo), onpressed pickimage, ), expanded( child textfield( controller messagecontroller, decoration inputdecoration collapsed(hinttext 'type a message'), ), ), iconbutton( icon icon(icons send), onpressed () { if ( messagecontroller text trim() isnotempty) { sendmessage(content messagecontroller text trim()); } }, ), ], ), ), ], ), ); } } explicación parselivelistwidget un widget que escucha las actualizaciones de consultas en vivo y se reconstruye cuando los datos cambian sendmessage() envía un mensaje de texto o una imagen pickimage() usa image picker para seleccionar una imagen y la envía como un mensaje setuplivequery() configura una consulta en vivo para escuchar nuevos mensajes en la sala de chat paso 8 – pruebas de la aplicación 8 1 ejecutar la aplicación en tu terminal, ejecuta flutter run 8 2 mensajería de pruebas abre la aplicación en dos dispositivos o emuladores regístrate o inicia sesión con diferentes cuentas de usuario desde una cuenta, selecciona al otro usuario de la lista de contactos envía mensajes e imágenes; deberían aparecer en tiempo real en ambos dispositivos conclusión ¡felicidades! has construido una aplicación de chat en tiempo real en flutter utilizando back4app esta aplicación soporta autenticación de usuario inicio de sesión y registro seguros mensajería en tiempo real actualizaciones instantáneas usando consultas en vivo presencia de usuario seguimiento del estado en línea/fuera de línea compartición de medios envío y recepción de imágenes historial de mensajes persistencia de mensajes de chat próximos pasos chats de grupo extender la aplicación para soportar conversaciones grupales estados de mensajes implementar recibos de lectura e indicadores de escritura notificaciones push enviar notificaciones para nuevos mensajes cuando la aplicación está en segundo plano imágenes de perfil permitir a los usuarios subir avatares mejoras de seguridad asegurar los datos con acls y permisos basados en roles recursos adicionales documentación de back4app https //www back4app com/docs guía de parse sdk para flutter https //docs parseplatform org/flutter/guide/ documentación oficial de flutter https //flutter dev/docs consulta en vivo de parse https //docs parseplatform org/js/guide/#live queries ¡feliz codificación!