1. Introducción
Última actualización: 16/11/2022
Cómo compilar una app para Android con Firebase y Jetpack Compose
En este codelab, compilarás una app para Android llamada Make It So. La IU de esta app está compilada por completo con Jetpack Compose, que es el kit de herramientas moderno de Android para compilar IU nativa. Es intuitivo y requiere menos código que escribir archivos .xml y vincularlos a actividades, fragmentos o vistas.
El primer paso para comprender qué tan bien funcionan juntos Firebase y Jetpack Compose es comprender la arquitectura moderna de Android. Una buena arquitectura hace que el sistema sea fácil de entender, desarrollar y mantener, ya que deja muy claro cómo se organizan los componentes y cómo se comunican entre sí. En el mundo de Android, la arquitectura recomendada se llama Modelo - Vista - ViewModel. El modelo representa la capa que accede a los datos en la aplicación. View es la capa de la IU y no debería saber nada sobre la lógica empresarial. Y en el ViewModel es donde se aplica la lógica empresarial, lo que a veces requiere que el ViewModel llame a la capa Model.
Te recomendamos que leas este artículo para comprender cómo se aplica Modelo - Vista - ViewModel a una app para Android compilada con Jetpack Compose, ya que esto facilitará la comprensión de la base de código y la realización de los próximos pasos.
Qué compilarás
Make It So es una aplicación simple de listas de tareas pendientes que permite al usuario agregar y editar tareas, agregar marcas, prioridades y fechas límite, y marcar las tareas como completadas. En las siguientes imágenes, se muestran las dos páginas principales de esta aplicación: la página de creación de tareas y la página principal con la lista de tareas creadas.
Agregarás algunas funciones que faltan en esta app:
- Autentica a los usuarios con un correo electrónico y una contraseña
- Agrega un objeto de escucha a una colección de Firestore y haz que la IU reaccione a los cambios
- Agrega seguimientos personalizados para supervisar el rendimiento de código específico en la app
- Crea un botón de activación de funciones con Remote Config y usa el lanzamiento por etapas para lanzarlo
Qué aprenderás
- Cómo usar Firebase Authentication, Performance Monitoring, Remote Config y Cloud Firestore en una aplicación para Android moderna
- Cómo hacer que las APIs de Firebase se ajusten a una arquitectura MVVM
- Cómo reflejar los cambios realizados con las APIs de Firebase en una IU de Compose
Requisitos
- Android Studio Flamingo+
- Android Emulator con el nivel de API 21 o una versión posterior
- Conocimientos del lenguaje de programación Kotlin
2. Obtén la app de ejemplo y configura Firebase
Obtén el código de la app de ejemplo
Clona el repositorio de GitHub a partir de la línea de comandos:
git clone https://github.com/FirebaseExtended/make-it-so-android.git
Crea un proyecto de Firebase
Lo primero que debes hacer es ir a Firebase console y crear un proyecto de Firebase haciendo clic en el botón "+ Agregar proyecto", como puedes ver a continuación:
Sigue los pasos que aparecen en pantalla para completar la creación del proyecto.
Agrega una app para Android a tu proyecto de Firebase
En tu proyecto de Firebase, puedes registrar diferentes apps: para Android, iOS, la Web, Flutter y Unity.
Elige la opción para Android, como se muestra aquí:
Luego, sigue estos pasos:
- Ingresa
com.example.makeitso
como el nombre del paquete y, de forma opcional, ingresa un sobrenombre. Para este codelab, no necesitas agregar el certificado de firma de depuración. - Haz clic en Siguiente para registrar tu app y acceder al archivo de configuración de Firebase.
- Haz clic en Download google-services.json para descargar el archivo de configuración y guardarlo en el directorio
make-it-so-android/app
. - Haz clic en Siguiente. Como los SDK de Firebase ya están incluidos en el archivo
build.gradle
del proyecto de ejemplo, haz clic en Siguiente para ir al paso Próximos pasos. - Haz clic en Ir a la consola para finalizar.
Para que la app de Make it So funcione correctamente, debes hacer dos cosas en la consola antes de pasar al código: habilitar los proveedores de autenticación y crear la base de datos de Firestore.
Configura la autenticación
Primero, habilitemos la autenticación para que los usuarios puedan acceder a la app:
- En el menú Build, selecciona Authentication y, luego, haz clic en Get Started.
- En la tarjeta Método de acceso, selecciona Correo electrónico/contraseña y habilítala.
- A continuación, haz clic en Agregar proveedor nuevo y selecciona y habilita Anónimo.
Configura Cloud Firestore
A continuación, configura Firestore. Usarás Firestore para almacenar las tareas de un usuario que accedió a su cuenta. Cada usuario tendrá su propio documento dentro de una colección de la base de datos.
- En el panel izquierdo de Firebase console, expande Compilación y, luego, selecciona Base de datos de Firestore.
- Haz clic en Crear base de datos.
- Deja el ID de la base de datos establecido en
(default)
. - Selecciona una ubicación para tu base de datos y, luego, haz clic en Siguiente.
Para una app real, debes elegir una ubicación que esté cerca de tus usuarios. - Haz clic en Iniciar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad.
En los próximos pasos de esta sección, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app públicamente sin agregar reglas de seguridad para tu base de datos. - Haz clic en Crear.
Tomemos un momento para crear reglas de seguridad sólidas en la base de datos de Firestore.
- Abre el panel de Firestore y ve a la pestaña Rules.
- Actualiza las reglas de seguridad para que se vean de la siguiente manera:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
}
}
}
Básicamente, estas reglas indican que cualquier usuario de la app que haya accedido a su cuenta puede crear un documento para sí mismo en cualquier colección. Luego, una vez creado, solo el usuario que lo creó podrá verlo, actualizarlo o borrarlo.
Ejecuta la aplicación
Ya puedes ejecutar la aplicación. Abre la carpeta make-it-so-android/start
en Android Studio y ejecuta la app (se puede hacer con Android Emulator o un dispositivo Android real).
3. Firebase Authentication
¿Qué función agregarás?
En el estado actual de la app de ejemplo Make It So, un usuario puede comenzar a usar la app sin tener que acceder primero. Para ello, usa la autenticación anónima. Sin embargo, las cuentas anónimas no permiten que un usuario acceda a sus datos en otros dispositivos ni en sesiones futuras. Si bien la autenticación anónima es útil para una integración previa, siempre debes proporcionarles a los usuarios la opción de cambiar a otro tipo de acceso. Con esto en mente, en este codelab, agregarás la autenticación de correo electrónico y contraseña a la app de Make It So.
¡Es hora de programar!
En cuanto el usuario crea una cuenta, escribiendo un correo electrónico y una contraseña, debes solicitar una credencial de correo electrónico a la API de Firebase Authentication y, luego, vincular la credencial nueva a la cuenta anónima. Abre el archivo AccountServiceImpl.kt
en Android Studio y actualiza la función linkAccount
para que se vea de la siguiente manera:
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
Ahora, abre SignUpViewModel.kt
y llama a la función linkAccount
del servicio dentro del bloque launchCatching
de la función onSignUpClick
:
screens/sign_up/SignUpViewModel.kt
launchCatching {
accountService.linkAccount(email, password)
openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}
Primero, intenta autenticarse y, si la llamada se realiza correctamente, pasa a la siguiente pantalla (SettingsScreen
). A medida que ejecutas estas llamadas dentro de un bloque launchCatching
, si se produce un error en la primera línea, se detectará y controlará la excepción, y no se llegará a la segunda línea.
En cuanto se vuelva a abrir el SettingsScreen
, debes asegurarte de que las opciones de Acceder y Crear cuenta ya no estén disponibles, ya que el usuario ya está autenticado. Para ello, hagamos que SettingsViewModel
escuche el estado del usuario actual (disponible en AccountService.kt
) para verificar si la cuenta es anónima o no. Para ello, actualiza el uiState
en SettingsViewModel.kt
para que se vea de la siguiente manera:
screens/settings/SettingsViewModel.kt
val uiState = accountService.currentUser.map {
SettingsUiState(it.isAnonymous)
}
Lo último que debes hacer es actualizar el uiState
en SettingsScreen.kt
para recopilar los estados emitidos por SettingsViewModel
:
screens/settings/SettingsScreen.kt
val uiState by viewModel.uiState.collectAsState(
initial = SettingsUiState(false)
)
Ahora, cada vez que cambie el usuario, SettingsScreen
se volverá a componer para mostrar las opciones según el nuevo estado de autenticación del usuario.
¡Es hora de probar!
Ejecuta Make it So y haz clic en el ícono de ajustes que se encuentra en la esquina superior derecha de la pantalla para navegar a la configuración. Allí, haz clic en la opción para crear una cuenta:
Escribe un correo electrónico válido y una contraseña segura para crear tu cuenta. Debería funcionar y deberías redireccionarte a la página de configuración, donde verás dos opciones nuevas: salir y borrar tu cuenta. Para verificar la cuenta nueva creada en el panel de Authentication de Firebase console, haz clic en la pestaña Usuarios.
4. Cloud Firestore
¿Qué función agregarás?
En el caso de Cloud Firestore, agregarás un objeto de escucha a la colección de Firestore que almacena los documentos que representan las tareas que se muestran en Make it So. Una vez que agregues este objeto de escucha, recibirás cada actualización que se realice en esta colección.
¡Es hora de programar!
Actualiza el Flow
disponible en StorageServiceImpl.kt
para que se vea de la siguiente manera:
model/service/impl/StorageServiceImpl.kt
override val tasks: Flow<List<Task>>
get() =
auth.currentUser.flatMapLatest { user ->
firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
}
Este código agrega un objeto de escucha a la colección de tareas según user.id
. Cada tarea está representada por un documento en una colección llamada tasks
, y cada una de ellas tiene un campo llamado userId
. Ten en cuenta que se emitirá un Flow
nuevo si cambia el estado de currentUser
(por ejemplo, si sales de tu cuenta).
Ahora debes hacer que el Flow
en TasksViewModel.kt
refleje lo mismo que en el servicio:
screens/tasks/TasksViewModel.kt
val tasks = storageService.tasks
Y lo último será hacer que composable function
en TasksScreens.kt
, que representa la IU, esté al tanto de este flujo y lo recopile como un estado. Cada vez que cambie el estado, la función de componibilidad se recompondrá automáticamente y mostrará el estado más reciente al usuario. Agrega lo siguiente a TasksScreen composable function
:
screens/tasks/TasksScreen.kt
val tasks = viewModel
.tasks
.collectAsStateWithLifecycle(emptyList())
Una vez que la función de componibilidad tenga acceso a estos estados, puedes actualizar LazyColumn
(que es la estructura que usas para mostrar una lista en la pantalla) para que se vea de la siguiente manera:
screens/tasks/TasksScreen.kt
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem( [...] )
}
}
¡Es hora de probar!
Para probar que funcionó, agrega una tarea nueva con la app (haz clic en el botón de agregar en la esquina inferior derecha de la pantalla). Una vez que termines de crear la tarea, debería aparecer en la colección de Firestore en Firestore console. Si accedes a Haz que suceda en otros dispositivos con la misma cuenta, podrás editar tus tareas pendientes y ver cómo se actualizan en todos los dispositivos en tiempo real.
5. Performance Monitoring
¿Qué función agregarás?
El rendimiento es un aspecto muy importante al que debes prestar atención, ya que es muy probable que los usuarios abandonen el uso de tu app si el rendimiento no es bueno y tarda demasiado en completar una tarea simple con ella. Por eso, a veces es útil recopilar algunas métricas sobre un recorrido específico que realiza un usuario en tu app. Para ayudarte con eso, Firebase Performance Monitoring ofrece seguimientos personalizados. Sigue los siguientes pasos para agregar seguimientos personalizados y medir el rendimiento en diferentes fragmentos de código en Make it So.
¡Es hora de programar!
Si abres el archivo Performance.kt
, verás una función intercalada llamada trace. Esta función llama a la API de Performance Monitoring para crear un seguimiento personalizado y pasar el nombre del seguimiento como parámetro. El otro parámetro que ves es el bloque de código que deseas supervisar. La métrica predeterminada recopilada para cada seguimiento es el tiempo que tarda en ejecutarse por completo:
model/service/Performance.kt
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
Puedes elegir qué partes de la base de código crees que son importantes para medir y agregar seguimientos personalizados. Este es un ejemplo de cómo agregar un registro personalizado a la función linkAccount
que viste antes (en AccountServiceImpl.kt
) en este codelab:
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
Ahora, es tu turno. Agrega algunos registros personalizados a la app de Make it So y continúa con la siguiente sección para probar si funcionó como se esperaba.
¡Es hora de probar!
Cuando termines de agregar los seguimientos personalizados, ejecuta la app y asegúrate de usar las funciones que deseas medir varias veces. Luego, ve a Firebase console y, luego, al Panel de rendimiento. En la parte inferior de la pantalla, encontrarás tres pestañas: Solicitudes de red, Registros personalizados y Renderización de pantalla.
Ve a la pestaña Custom traces y verifica que los seguimientos que agregaste en la base de código se muestren allí y que puedas ver cuánto tiempo suele tardar en ejecutarse estos fragmentos de código.
6. Remote Config
¿Qué función agregarás?
Existen muchos casos de uso para Remote Config, desde cambiar la apariencia de tu app de forma remota hasta configurar diferentes comportamientos para diferentes segmentos de usuarios. En este codelab, usarás Remote Config para crear un botón de activación de funciones que muestre o oculte la nueva función editar tarea en la app de Make it So.
¡Es hora de programar!
Lo primero que debes hacer es crear la configuración en Firebase console. Para ello, debes navegar al panel de Remote Config y hacer clic en el botón Agregar parámetro. Completa los campos según la siguiente imagen:
Una vez que hayas completado todos los campos, puedes hacer clic en el botón Guardar y, luego, en Publicar. Ahora que el parámetro se creó y está disponible para tu base de código, debes agregar el código que recuperará los valores nuevos en tu app. Abre el archivo ConfigurationServiceImpl.kt
y actualiza la implementación de estas dos funciones:
model/service/impl/ConfigurationServiceImpl.kt
override suspend fun fetchConfiguration(): Boolean {
return remoteConfig.fetchAndActivate().await()
}
override val isShowTaskEditButtonConfig: Boolean
get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()
La primera función recupera los valores del servidor y se le llama en cuanto se inicia la app, en SplashViewModel.kt
. Es la mejor manera de garantizar que los valores más actualizados estén disponibles en todas las pantallas desde el principio. No es una buena experiencia del usuario si cambias la IU o el comportamiento de la app más adelante, cuando el usuario está en medio de hacer algo.
La segunda función muestra el valor booleano que se publicó para el parámetro que acabas de crear en la consola. Además, deberás recuperar esta información en TasksViewModel.kt
. Para ello, agrega lo siguiente a la función loadTaskOptions
:
screens/tasks/TasksViewModel.kt
fun loadTaskOptions() {
val hasEditOption = configurationService.isShowTaskEditButtonConfig
options.value = TaskActionOption.getOptions(hasEditOption)
}
Recuperas el valor de la primera línea y lo usas para cargar las opciones del menú de los elementos de tarea de la segunda línea. Si el valor es false
, significa que el menú no contendrá la opción de edición. Ahora que tienes la lista de opciones, debes hacer que la IU la muestre correctamente. Cuando compilas una app con Jetpack Compose, debes buscar el composable function
que declara cómo debe verse la IU de TasksScreen
. Por lo tanto, abre el archivo TasksScreen.kt
y actualiza la LazyColum
para que apunte a las opciones disponibles en TasksViewModel.kt
:
screens/tasks/TasksScreen.kt
val options by viewModel.options
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem(
options = options,
[...]
)
}
}
El TaskItem
es otro composable function
que declara cómo debería verse la IU de una sola tarea. Además, cada tarea tiene un menú con opciones que se muestra cuando el usuario hace clic en el ícono de tres puntos al final.
¡Es hora de probar!
Ya puedes ejecutar la app. Verifica que el valor que publicaste con Firebase console coincida con el comportamiento de la app:
- Si es
false
, solo deberías ver dos opciones cuando hagas clic en el ícono de tres puntos. - Si es
true
, deberías ver tres opciones cuando hagas clic en el ícono de tres puntos.
Intenta cambiar el valor un par de veces en Play Console y reinicia la app. Así de fácil es lanzar funciones nuevas en tu app con Remote Config.
7. Felicitaciones
¡Felicitaciones! Compilaste correctamente una app para Android con Firebase y Jetpack Compose.
Agregaste Firebase Authentication, Performance Monitoring, Remote Config y Cloud Firestore a una app para Android compilada por completo con Jetpack Compose para la IU y la ajustaste a la arquitectura MVVM recomendada.
Lecturas adicionales
- Cómo compilar una app para Android con Firebase y Compose
- Cómo agregar Firebase Authentication a una app de Jetpack Compose
- Cómo agregar Cloud Firestore a una app de Jetpack Compose
- Cómo agregar corrutinas y Flow a una app para Android compilada con Firebase y Compose
- Cómo agregar Firebase Performance Monitoring a una app de Jetpack Compose
- Cómo agregar Firebase Remote Config a una app de Jetpack Compose