1. Descripción general
Te damos la bienvenida al codelab de FriendlyChat para iOS. En este codelab, aprenderás a compilar una aplicación de chat para iOS en tiempo real con todas las funciones usando Firebase y funciones modernas de Swift, como SwiftUI, Swift Concurrency y el framework de Observation.
Qué aprenderás
- Administra el estado con el framework de Observation moderno (
@Observable). - Autentica usuarios con Firebase Authentication.
- Sincroniza mensajes de chat en tiempo real con Cloud Firestore.
- Almacena y publica imágenes con Cloud Storage para Firebase.
- Accede a las APIs de Firebase con las funciones modernas de Swift Concurrency.
Requisitos
- La versión más reciente de Xcode
- Un simulador de iOS o un dispositivo de prueba físico
- Una Cuenta de Google para crear y administrar tu proyecto de Firebase
2. Obtén el código de muestra
Clona el repositorio de GitHub a partir de la línea de comandos:
$ git clone https://github.com/firebase/codelab-friendlychat-ios
El repositorio codelab-friendlychat-ios contiene varios proyectos de muestra:
ios-starter/swift-starter: Es el proyecto de Xcode inicial que contiene el esqueleto de diseño de SwiftUI y los comentariosTODOen los que implementarás las funciones de la app con Firebase.ios/swift: Es el proyecto de Xcode completado con la aplicación de muestra finalizada.
3. Compila la app de partida
Compila y ejecuta la aplicación inicial para familiarizarte con la interfaz de usuario:
- En Finder o Terminal, navega al directorio
ios-starter/swift-starter. - Haz doble clic en
FriendlyChatSwift.xcodeprojpara abrir el proyecto en Xcode. - Ten en cuenta que Xcode resuelve automáticamente las dependencias de Swift Package Manager en segundo plano (descarga
firebase-ios-sdkv12+ de GitHub). - Selecciona un simulador de iOS (por ejemplo, iPhone 17 Pro) y haz clic en el botón Ejecutar (cmd+R).
Después de unos segundos, aparecerá la pantalla de acceso de FriendlyChat. En este punto, los botones de acceso y los feeds de mensajes son marcadores de posición. Conectarás Firebase a la app en los siguientes pasos.
4. Configura un proyecto de Firebase
Crea un proyecto de Firebase nuevo
- Accede a la Firebase console con tu Cuenta de Google.
- Haz clic en el botón para crear un proyecto nuevo y, luego, ingresa un nombre de proyecto (por ejemplo,
FriendlyChat).
- Haz clic en Continuar.
- Si se te solicita, revisa y acepta las Condiciones de Firebase y, luego, haz clic en Continuar.
- (Opcional) Habilita la asistencia de IA en Firebase console (llamada "Gemini en Firebase").
- Para este codelab, no necesitas Google Analytics, por lo que debes desactivar la opción de Google Analytics.
- Haz clic en Crear proyecto, espera a que se aprovisione tu proyecto y, luego, haz clic en Continuar.
Actualiza tu plan de precios de Firebase
Para usar Cloud Storage para Firebase, tu proyecto de Firebase debe tener el plan de precios de pago por uso (Blaze), lo que significa que está vinculado a una cuenta de Facturación de Cloud.
- Una cuenta de Facturación de Cloud requiere una forma de pago, como una tarjeta de crédito.
- Si es la primera vez que usas Firebase y Google Cloud, verifica si cumples con los requisitos para obtener un crédito de$300 y una cuenta de Facturación de Cloud de prueba gratuita.
- Si realizas este codelab como parte de un evento, pregúntale al organizador si hay créditos de Cloud disponibles.
Para actualizar tu proyecto al plan Blaze, sigue estos pasos:
- En Firebase console, selecciona la opción para actualizar tu plan.
- Selecciona el plan Blaze. Sigue las instrucciones en pantalla para vincular una cuenta de Facturación de Cloud a tu proyecto.
Si necesitas crear una cuenta de Facturación de Cloud como parte de esta actualización, es posible que debas volver a la actualización. en Firebase console para completar la actualización.
Conecta tu app para iOS
- En la pantalla Descripción general del proyecto, haz clic en el ícono de iOS para iniciar el flujo de trabajo de configuración de la app.
- Ingresa el ID del paquete:
com.google.firebase.codelab.FriendlyChatSwift - Haz clic en Registrar app.
Agrega GoogleService-Info.plist a tu proyecto de Xcode
- Haz clic en Descargar GoogleService-Info.plist para guardar el archivo de configuración.
- En Xcode, arrastra el archivo
GoogleService-Info.plistdescargado al grupo principalFriendlyChatSwiften el navegador del proyecto. - Cuando se te solicite, asegúrate de que la opción Copiar los elementos si es necesario esté marcada y que el destino
FriendlyChatSwiftesté seleccionado. Luego, haz clic en Finalizar.
Configura Firebase en FriendlyChatSwiftApp.swift
Por último, inicializa Firebase con la configuración de tu proyecto cuando se inicie la aplicación de SwiftUI. Abre FriendlyChatSwiftApp.swift y reemplaza los marcadores de posición TODO por import FirebaseCore y FirebaseApp.configure():
import SwiftUI
import FirebaseCore
@main
struct FriendlyChatSwiftApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
5. Autenticar usuarios
Configura la autenticación en Firebase console
Antes de poder autenticar a los usuarios, primero debes habilitar el proveedor de autenticación que elijas en Firebase console. En este instructivo, se usa la autenticación con correo electrónico y contraseña:
- En Firebase console, ve a Seguridad > Authentication y, luego, haz clic en Comenzar.
- Selecciona la pestaña Método de acceso.
- Haz clic en Correo electrónico/contraseña, en el botón de activación Habilitar y en Guardar.
Protege Cloud Firestore con reglas de autenticación
A continuación, exige que los usuarios se autentiquen antes de leer o escribir mensajes:
- En Firebase console, ve a Bases de datos y almacenamiento > Base de datos de Firestore y, luego, haz clic en Crear base de datos.
- Selecciona una ubicación y haz clic en Siguiente.
- Selecciona Iniciar en modo de prueba y haz clic en Crear.
- Selecciona la pestaña Reglas y actualiza las reglas de seguridad a lo siguiente:
Estas reglas permiten que cualquier usuario autenticado lea o escriba mensajes en la base de datos, lo que es adecuado para fines de aprendizaje. Obtén más información sobre las reglas de seguridad en la documentación de las reglas de seguridad.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /messages/{messageId} { allow read, write: if request.auth != null; } } } - Haz clic en Publicar.
Observa el estado de autenticación en UserViewModel.swift
En SwiftUI, observar el estado de Firebase Auth de forma reactiva garantiza que la IU cambie sin problemas entre la pantalla de acceso y la interfaz de chat.
Abre ViewModels/UserViewModel.swift y reemplaza el TODO en init() para observar los cambios de estado de autenticación con authStateChanges AsyncSequence:
init() {
authTask = Task {
for await user in Auth.auth().authStateChanges {
self.user = user
}
}
}
Implementa el acceso, el registro y el cierre de sesión con Swift Concurrency
En UserViewModel.swift, reemplaza los comentarios TODO restantes por los métodos modernos de autenticación async/await:
func signIn(email: String, password: String) async {
errorMessage = nil
if email.isEmpty || password.isEmpty {
showError("Please enter both email and password.")
return
}
do {
try await Auth.auth().signIn(withEmail: email, password: password)
} catch {
showError(error.localizedDescription)
}
}
func signUp(email: String, password: String, displayName: String) async {
errorMessage = nil
if email.isEmpty || password.isEmpty {
showError("Please enter both email and password.")
return
}
do {
let result =
try await Auth.auth().createUser(withEmail: email, password: password)
let changeRequest = result.user.createProfileChangeRequest()
changeRequest.displayName = displayName.isEmpty ? email : displayName
try await changeRequest.commitChanges()
self.user = Auth.auth().currentUser
} catch {
showError(error.localizedDescription)
}
}
func updateDisplayName(_ displayName: String) async {
guard let currentUser = Auth.auth().currentUser else { return }
do {
let changeRequest = currentUser.createProfileChangeRequest()
changeRequest.displayName = displayName
try await changeRequest.commitChanges()
self.user = Auth.auth().currentUser
} catch {
showError(error.localizedDescription)
}
}
func signOut() {
do {
try Auth.auth().signOut()
} catch {
showError(error.localizedDescription)
}
}
Prueba la autenticación de usuarios
- Haz clic en el botón Ejecutar en Xcode.
- En el simulador de la app, haz clic en Registrarse, ingresa un nombre visible, un correo electrónico y una contraseña, y presiona REGISTRARSE.
- Deberías autenticarte automáticamente y navegar a la pantalla de mensajería vacía.
6. Lee desde Cloud Firestore
Agrega mensajes de muestra en Firebase console
Completa la base de datos con mensajes de muestra:
- En Firebase console, ve a Base de datos de Firestore y selecciona la pestaña Datos.
- Haz clic en Iniciar colección.
- Ingresa
messagespara el ID de la colección y, luego, haz clic en Siguiente. - Deja el ID del documento configurado para que se genere automáticamente (o haz clic en ID automático).
- Agrega los siguientes campos al documento:
text(tipo:string, valor:Hello)displayName(tipo:string, valor:anonymous)
- Haz clic en Guardar.
- De manera opcional, haz clic en Agregar documento para agregar más mensajes de muestra.
Sincroniza mensajes en FriendlyMessageViewModel.swift
En SwiftUI, un modelo @Observable controla las actualizaciones declarativas de la IU. Abre ViewModels/FriendlyMessageViewModel.swift y, luego, implementa startListening() y stopListening() con snapshots AsyncSequence:
func startListening() {
stopListening()
listenerTask = Task {
let db = Firestore.firestore()
do {
for try await snapshot in db.collection("messages").snapshots {
self.messages = snapshot.documents.compactMap { document in
try? document.data(as: FriendlyMessage.self)
}
}
} catch {
print("Error listening for messages: \(error)")
}
}
}
func stopListening() {
listenerTask?.cancel()
listenerTask = nil
messages.removeAll()
}
Cómo SwiftUI renderiza y desplaza automáticamente los mensajes
En Views/ContentView.swift, observa cómo ScrollViewReader y LazyVStack renderizan burbujas de chat y se desplazan automáticamente al mensaje más reciente cada vez que cambia messages.count:
ScrollViewReader { scrollViewReader in
ScrollView {
LazyVStack(spacing: 12) {
ForEach(messageViewModel.messages) { message in
FriendlyMessageView(friendlyMessage: message)
.id(message.id)
}
}
.padding(.horizontal)
.onChange(of: messageViewModel.messages.count) { _, count in
guard count > 0,
let lastId = messageViewModel.messages.last?.id else { return }
withAnimation(.easeInOut) {
scrollViewReader.scrollTo(lastId, anchor: .bottom)
}
}
}
}
Al vincular el estado de la base de datos directamente al estado de la IU a través del modelo de vista, SwiftUI permite que el código de la app asigne transiciones a animaciones de forma clara. En el siguiente paso, escribirás datos en la base de datos desde la app para observar esta animación en acción.
7. Enviar mensajes
Implementa sendMessage con Swift Concurrency
Cuando agregas un documento a una colección con addDocument(), Cloud Firestore genera un ID único para cada mensaje de chat.
En ViewModels/FriendlyMessageViewModel.swift, reemplaza el TODO en sendMessage(text:imageUrl:) por un método async throws:
func sendMessage(text: String?, imageUrl: String?) async throws {
guard let currentUser = Auth.auth().currentUser else { return }
let message = FriendlyMessage(
text: text,
displayName: currentUser.displayName ?? currentUser.email ?? "Anonymous",
imageUrl: imageUrl,
userId: currentUser.uid
)
let db = Firestore.firestore()
_ = try db.collection("messages").addDocument(from: message)
}
Pruebe enviar mensajes
- Haz clic en el botón Ejecutar en Xcode.
- Accede a tu cuenta.
- Escribe un mensaje en el campo de texto inferior y presiona el ícono Enviar.
- Mira cómo aparece el mensaje de forma instantánea en tu simulador.
8. Almacena y recibe imágenes
Configura Cloud Storage para Firebase
- En Firebase console, ve a Bases de datos y almacenamiento > Storage y, luego, haz clic en Comenzar.
- Selecciona Iniciar en modo de prueba y haz clic en Siguiente.
- Acepta la ubicación de almacenamiento predeterminada y haz clic en Listo.
Selección de imágenes nativas con PhotosPicker de SwiftUI
SwiftUI moderno (iOS 16+) proporciona la selección de fotos nativa a través de PhotosPicker desde import PhotosUI. No se requieren puentes de delegados de UIKit ni wrappers de UIImagePickerController.
En Views/FooterView.swift, observa cómo PhotosPicker vincula las imágenes seleccionadas:
PhotosPicker(selection: $selectedItem, matching: .images) {
Image(systemName: "photo.on.rectangle.angled")
.font(.system(size: 26))
.foregroundStyle(.blue)
.accessibilityLabel("Select photo")
}
.onChange(of: selectedItem) { _, newItem in
Task {
if let data = try? await newItem?.loadTransferable(type: Data.self) {
await uploadAndSendImage(data: data)
}
}
}
Implementa la carga de imágenes
Cuando se selecciona una foto, sube los datos de la imagen a Cloud Storage y guarda la URL de descarga pública en Cloud Firestore.
En Views/FooterView.swift, reemplaza el TODO en uploadAndSendImage(data:):
private func uploadAndSendImage(data: Data) async {
guard let uid = Auth.auth().currentUser?.uid else { return }
isUploading = true
defer {
isUploading = false
selectedItem = nil
}
do {
let filename = "\(uid)/\(UUID().uuidString).jpg"
let storageRef =
Storage.storage().reference().child("images").child(filename)
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
_ = try await storageRef.putDataAsync(data, metadata: metadata)
let downloadURL = try await storageRef.downloadURL()
try await viewModel.sendMessage(
text: nil, imageUrl: downloadURL.absoluteString)
} catch {
print("Error uploading image: \(error.localizedDescription)")
}
}
Comparte imágenes con Cloud Storage
En Views/FriendlyMessageImageView.swift, las URLs de las imágenes se cargan de forma asíncrona con Swift Concurrency y el SDK de Cloud Storage:
- Las URLs de descarga HTTP/HTTPS estándar se recuperan de forma asíncrona a través de
URLSession. - Las URLs de Google Cloud Storage (por ejemplo,
gs://...) se recuperan conStorage.storage().reference(forURL:).
Prueba los mensajes de imágenes
- Haz clic en el botón Ejecutar en Xcode.
- Accede a tu cuenta.
- Presiona el ícono de foto, elige una imagen de la biblioteca y observa cómo se sube y aparece en el chat.
9. Conclusión
Felicitaciones, compilaste correctamente una aplicación de chat para iOS en tiempo real con Swift y Firebase.
Qué aprendiste
- Integración de Swift Package Manager (SPM) en Xcode para
firebase-ios-sdk. - Diseños declarativos de SwiftUI ,
PhotosPickery desplazamiento automático deScrollViewReader. - Swift Concurrency (
async/await) en Authentication, Cloud Firestore y Cloud Storage. - Autenticación con correo electrónico y contraseña y anónima con observación de estado reactiva.
- Escucha de instantáneas en tiempo real de Cloud Firestore y escrituras de ID automatizadas.
- Cargas binarias de Cloud Storage para Firebase y URLs de descarga públicas.