1. Información general
Bienvenido al codelab de Friendly Chat. En este codelab, aprenderá cómo usar la plataforma Firebase para crear aplicaciones de iOS. Implementarás un cliente de chat y monitorearás su rendimiento usando Firebase.
lo que aprenderás
- Permitir que los usuarios inicien sesión.
- Sincronice datos utilizando Firebase Realtime Database.
- Almacene archivos binarios en Firebase Storage.
Lo que necesitarás
- Xcode
- CacaoPods
- Un dispositivo de prueba con iOS 8.0+ o simulador
¿Cómo utilizarás este tutorial?
¿Cómo calificaría su experiencia con la creación de aplicaciones para iOS?
2. Obtenga el código de muestra
Clona el repositorio de GitHub desde la línea de comando.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Cree la aplicación de inicio
Para crear la aplicación de inicio:
- En una ventana de terminal, navegue hasta el directorio
ios-starter/swift-starter
desde la descarga del código de muestra - Ejecute
pod install --repo-update
- Abra el archivo FriendlyChatSwift.xcworkspace para abrir el proyecto en Xcode.
- Haga clic en el Botón ejecutar .
Deberías ver aparecer la pantalla de inicio de Friendly Chat después de unos segundos. Debería aparecer la interfaz de usuario. Sin embargo, en este punto no puede iniciar sesión, enviar ni recibir mensajes. La aplicación se cancelará con una excepción hasta que completes el siguiente paso.
4. Crear proyecto de consola Firebase
Crear proyecto
Desde la consola de Firebase , seleccione Agregar proyecto .
Llame al proyecto FriendlyChat
, luego haga clic en Crear proyecto .
Conecte su aplicación iOS
- En la pantalla Descripción general del proyecto de tu nuevo proyecto, haz clic en Agregar Firebase a tu aplicación de iOS .
- Ingrese el ID del paquete, como "
com.google.firebase.codelab.FriendlyChatSwift
". - Ingrese la identificación de la App Store como "
123456
". - Haga clic en Registrar aplicación .
Agregue el archivo GoogleService-Info.plist a su aplicación
En la segunda pantalla, haga clic en Descargar GoogleService-Info.plist para descargar un archivo de configuración que contiene todos los metadatos de Firebase necesarios para su aplicación. Copie ese archivo a su aplicación y agréguelo al destino FriendlyChatSwift .
Ahora puede hacer clic en la "x" en la esquina superior derecha de la ventana emergente para cerrarla (omitiendo los pasos 3 y 4), ya que realizará esos pasos aquí.
Importar módulo Firebase
Comience asegurándose de que el módulo Firebase
esté importado.
AppDelegate.swift , FCViewController.swift
import Firebase
Configurar Firebase en AppDelegate
Utilice el método "configure" en FirebaseApp dentro de la función application:didFinishLaunchingWithOptions para configurar los servicios subyacentes de Firebase desde su archivo .plist.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().delegate = self
return true
}
5. Identificar usuarios
Utilice reglas para restringir a usuarios autenticados
Ahora agregaremos una regla para requerir autenticación antes de leer o escribir cualquier mensaje. Para hacer esto agregamos las siguientes reglas a nuestro objeto de datos de mensajes. Desde la sección Base de datos de Firebase console , seleccione Base de datos en tiempo real y luego haga clic en la pestaña Reglas. Luego actualice las reglas para que se vean así:
{
"rules": {
"messages": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Para obtener más información sobre cómo funciona esto (incluida la documentación sobre la variable "auth"), consulte la documentación de seguridad de Firebase.
Configurar API de autenticación
Antes de que su aplicación pueda acceder a las API de autenticación de Firebase en nombre de sus usuarios, deberá habilitarla
- Navegue a la consola Firebase y seleccione su proyecto
- Seleccionar autenticación
- Seleccione la pestaña Método de inicio de sesión
- Mueva el interruptor de Google a habilitado (azul)
- Presione Guardar en el cuadro de diálogo resultante.
Si recibes errores más adelante en este codelab con el mensaje "CONFIGURATION_NOT_FOUND", vuelve a este paso y vuelve a verificar tu trabajo.
Confirmar la dependencia de Firebase Auth
Confirme que existen dependencias de Firebase Auth en el archivo Podfile
.
archivo de pods
pod 'Firebase/Auth'
Configure su Info.plist para iniciar sesión en Google.
Deberá agregar un esquema de URL personalizado a su proyecto XCode.
- Abra la configuración de su proyecto: haga doble clic en el nombre del proyecto en la vista de árbol de la izquierda. Seleccione su aplicación en la sección OBJETIVOS, luego seleccione la pestaña Información y expanda la sección Tipos de URL.
- Haga clic en el botón + y agregue un esquema de URL para su ID de cliente invertido. Para encontrar este valor, abra el archivo de configuración GoogleService-Info.plist y busque la clave REVERSED_CLIENT_ID. Copie el valor de esa clave y péguelo en el cuadro Esquemas de URL en la página de configuración. Deje los demás campos en blanco.
- Cuando esté completa, su configuración debería verse similar a la siguiente (pero con los valores específicos de su aplicación):
Establecer ID de cliente para iniciar sesión en Google
Una vez configurado Firebase, podemos usar el ID de cliente para configurar el inicio de sesión de Google dentro del método "didFinishLaunchingWithOptions:".
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
return true
}
Agregar el controlador de inicio de sesión
Una vez que el resultado del inicio de sesión de Google haya sido exitoso, use la cuenta para autenticarse con Firebase.
AppDelegate.swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
if let error = error {
print("Error \(error)")
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
print("Error \(error)")
return
}
}
}
Iniciar sesión automáticamente como usuario. Luego agregue un oyente a Firebase Auth, para permitir que el usuario ingrese a la aplicación, después de iniciar sesión correctamente. Y elimine el oyente en deinit.
SignInViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().signInSilently()
handle = Auth.auth().addStateDidChangeListener() { (auth, user) in
if user != nil {
MeasurementHelper.sendLoginEvent()
self.performSegue(withIdentifier: Constants.Segues.SignInToFp, sender: nil)
}
}
}
deinit {
if let handle = handle {
Auth.auth().removeStateDidChangeListener(handle)
}
}
Desconectar
Agregar el método de cerrar sesión
FCViewController.swift
@IBAction func signOut(_ sender: UIButton) {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
dismiss(animated: true, completion: nil)
} catch let signOutError as NSError {
print ("Error signing out: \(signOutError.localizedDescription)")
}
}
Pruebe la lectura de mensajes como usuario registrado
- Haga clic en el Botón ejecutar .
- Debería ser enviado inmediatamente a la pantalla de inicio de sesión. Toque el botón Iniciar sesión con Google.
- Luego debería ser enviado a la pantalla de mensajes si todo funcionó bien.
6. Activar la base de datos en tiempo real
Importar mensajes
En su proyecto en Firebase console, seleccione el elemento Base de datos en la barra de navegación izquierda. En el menú adicional de la base de datos, seleccione Importar JSON . Busque el archivo initial_messages.json
en el directorio amigable de chat, selecciónelo y luego haga clic en el botón Importar . Esto reemplazará cualquier dato que se encuentre actualmente en su base de datos. También puede editar la base de datos directamente, usando el + verde y la x roja para agregar y eliminar elementos.
Después de importar su base de datos debería verse así:
Confirmar la dependencia de la base de datos de Firebase
En el bloque de dependencias del archivo Podfile
, confirme que Firebase/Database
esté incluido.
archivo de pods
pod 'Firebase/Database'
Sincronizar mensajes existentes
Agregue código que sincronice los mensajes recién agregados con la interfaz de usuario de la aplicación.
El código que agregue en esta sección:
- Inicialice la base de datos de Firebase y agregue un oyente para manejar los cambios realizados en la base de datos.
- Actualice el
DataSnapshot
para que se muestren los nuevos mensajes.
Modifique los métodos "deinit", "configureDatabase" y "tableView:cellForRow indexPath:" de su FCViewController; reemplácelo con el código definido a continuación:
FCViewController.swift
deinit {
if let refHandle = _refHandle {
self.ref.child("messages").removeObserver(withHandle: _refHandle)
}
}
func configureDatabase() {
ref = Database.database().reference()
// Listen for new messages in the Firebase database
_refHandle = self.ref.child("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
guard let strongSelf = self else { return }
strongSelf.messages.append(snapshot)
strongSelf.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Dequeue cell
let cell = self.clientTable.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
// Unpack message from Firebase DataSnapshot
let messageSnapshot = self.messages[indexPath.row]
guard let message = messageSnapshot.value as? [String: String] else { return cell }
let name = message[Constants.MessageFields.name] ?? ""
let text = message[Constants.MessageFields.text] ?? ""
cell.textLabel?.text = name + ": " + text
cell.imageView?.image = UIImage(named: "ic_account_circle")
if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
let data = try? Data(contentsOf: URL) {
cell.imageView?.image = UIImage(data: data)
}
return cell
}
Sincronización de mensajes de prueba
- Haga clic en el Botón ejecutar .
- Haga clic en el botón Iniciar sesión para comenzar para ir a la ventana de mensajes.
- Agregue nuevos mensajes directamente en Firebase console haciendo clic en el símbolo + verde al lado de la entrada "mensajes" y agregando un objeto como el siguiente:
- Confirme que aparecen en la interfaz de usuario de Friendly-Chat.
7. Enviar mensajes
Implementar Enviar mensaje
Enviar valores a la base de datos. Cuando utiliza el método push para agregar datos a Firebase Realtime Database, se agregará una identificación automática. Estas identificaciones generadas automáticamente son secuenciales, lo que garantiza que se agregarán nuevos mensajes en el orden correcto.
Modifique el método "sendMessage:" de su FCViewController; reemplácelo con el código definido a continuación:
FCViewController.swift
func sendMessage(withData data: [String: String]) {
var mdata = data
mdata[Constants.MessageFields.name] = Auth.auth().currentUser?.displayName
if let photoURL = Auth.auth().currentUser?.photoURL {
mdata[Constants.MessageFields.photoURL] = photoURL.absoluteString
}
// Push data to Firebase Database
self.ref.child("messages").childByAutoId().setValue(mdata)
}
Prueba de envío de mensajes
- Haga clic en el Botón ejecutar .
- Haga clic en Iniciar sesión para ir a la ventana de mensajes.
- Escribe un mensaje y presiona enviar. El nuevo mensaje debería estar visible en la interfaz de usuario de la aplicación y en Firebase console.
8. Almacenar y recibir imágenes
Confirmar la dependencia del almacenamiento de Firebase
En el bloque de dependencias del Podfile
, confirme Firebase/Storage
esté incluido.
archivo de pods
pod 'Firebase/Storage'
Activar Firebase Storage en el panel
Vaya a la consola de Firebase y confirme que el almacenamiento esté activado con el dominio "gs://PROJECTID.appspot.com"
Si en su lugar ve la ventana de activación, haga clic en "COMENZAR" para activarla con las reglas predeterminadas.
Configurar FirebaseStorage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
Recibir imágenes en mensajes existentes
Agregue código que descargue imágenes de Firebase Storage.
Modifique el método "tableView: cellForRowAt indexPath:" de su FCViewController; reemplácelo con el código definido a continuación:
FCViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Dequeue cell
let cell = self.clientTable .dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
// Unpack message from Firebase DataSnapshot
let messageSnapshot: DataSnapshot! = self.messages[indexPath.row]
guard let message = messageSnapshot.value as? [String:String] else { return cell }
let name = message[Constants.MessageFields.name] ?? ""
if let imageURL = message[Constants.MessageFields.imageURL] {
if imageURL.hasPrefix("gs://") {
Storage.storage().reference(forURL: imageURL).getData(maxSize: INT64_MAX) {(data, error) in
if let error = error {
print("Error downloading: \(error)")
return
}
DispatchQueue.main.async {
cell.imageView?.image = UIImage.init(data: data!)
cell.setNeedsLayout()
}
}
} else if let URL = URL(string: imageURL), let data = try? Data(contentsOf: URL) {
cell.imageView?.image = UIImage.init(data: data)
}
cell.textLabel?.text = "sent by: \(name)"
} else {
let text = message[Constants.MessageFields.text] ?? ""
cell.textLabel?.text = name + ": " + text
cell.imageView?.image = UIImage(named: "ic_account_circle")
if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
let data = try? Data(contentsOf: URL) {
cell.imageView?.image = UIImage(data: data)
}
}
return cell
}
9. Enviar mensajes con imágenes
Implementar almacenar y enviar imágenes
Cargue una imagen del usuario, luego sincronice la URL de almacenamiento de esta imagen con la base de datos para que esta imagen se envíe dentro del mensaje.
Modifique el método "imagePickerController: didFinishPickingMediaWithInfo:" de su FCViewController; reemplácelo con el código definido a continuación:
FCViewController.swift
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion:nil)
guard let uid = Auth.auth().currentUser?.uid else { return }
// if it's a photo from the library, not an image from the camera
if #available(iOS 8.0, *), let referenceURL = info[UIImagePickerControllerReferenceURL] as? URL {
let assets = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
let asset = assets.firstObject
asset?.requestContentEditingInput(with: nil, completionHandler: { [weak self] (contentEditingInput, info) in
let imageFile = contentEditingInput?.fullSizeImageURL
let filePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000))/\((referenceURL as AnyObject).lastPathComponent!)"
guard let strongSelf = self else { return }
strongSelf.storageRef.child(filePath)
.putFile(from: imageFile!, metadata: nil) { (metadata, error) in
if let error = error {
let nsError = error as NSError
print("Error uploading: \(nsError.localizedDescription)")
return
}
strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
}
})
} else {
guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
let imageData = UIImageJPEGRepresentation(image, 0.8)
let imagePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000)).jpg"
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
self.storageRef.child(imagePath)
.putData(imageData!, metadata: metadata) { [weak self] (metadata, error) in
if let error = error {
print("Error uploading: \(error)")
return
}
guard let strongSelf = self else { return }
strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
}
}
}
Prueba de envío y recepción de mensajes con imágenes
- Haga clic en el Botón ejecutar .
- Haga clic en Iniciar sesión para ir a la ventana de mensajes.
- Haga clic en el icono "agregar una foto" para elegir una foto. El nuevo mensaje con la foto debería estar visible en la interfaz de usuario de la aplicación y en Firebase console.
10. ¡Felicitaciones!
Ha utilizado Firebase para crear fácilmente una aplicación de chat en tiempo real.
Lo que hemos cubierto
- Base de datos en tiempo real
- Inicio de sesión federado
- Almacenamiento