Este codelab es parte del curso Aspectos avanzados de Android en Kotlin. Aprovecharás al máximo este curso si trabajas con los codelabs en secuencia, pero no es obligatorio. Todos los codelabs del curso se detallan en la página de destino de Codelabs avanzados de Android en Kotlin.
Introducción
A la hora de compilar una app para Android, existen muchos beneficios que pueden provenir de la compatibilidad de accesos para los usuarios. Si permites que los usuarios creen una identidad dentro de tu app, puedes brindarles más formas de interactuar con ella.
Con las cuentas personalizadas, los usuarios pueden personalizar su experiencia en la app, interactuar con otros usuarios y mantener sus datos persistentes y transferirlos si usan la app en otro dispositivo (como la Web o un teléfono nuevo).
En este codelab, aprenderás los conceptos básicos sobre cómo admitir el acceso de tu app mediante la biblioteca de FirebaseUI. Entre muchas cosas más, la biblioteca de FirebaseUI facilita la tarea para los desarrolladores que desean compilar un flujo de acceso, y se encarga de administrar las cuentas de usuario por ti.
Conocimientos que ya deberías tener
- Conceptos básicos sobre cómo compilar una app para Android
- LiveData y ViewModel
Qué aprenderás
- Cómo agregar Firebase a tu proyecto
- Cómo admitir el acceso en una app para Android
- Cómo observar el estado de autenticación actual de tu app
- Cómo cerrar la sesión de los usuarios
Actividades
- Usa Firebase console para integrar Firebase en tu app.
- Implementa la función de acceso.
- Agrega personalizaciones en la app para los usuarios que hayan accedido.
- Implementa el cierre de sesión de usuarios.
Más información sobre LiveData y ViewModel
Para la app de este codelab, necesitas conocimientos básicos sobre LiveData y ViewModel. Lee las descripciones generales de LiveData y ViewModel si quieres obtener una breve descripción general de estos conceptos.
También puedes realizar el curso Desarrollo de apps para Android con Kotlin a fin de obtener información sobre temas fundamentales de Android que encontrarás como parte de este codelab. Ese curso está disponible como curso de Udacity y curso de codelabs.
En este codelab, compilarás una app que muestra datos divertidos de Android. Y, lo que es más importante, la app tendrá un botón de Acceder/Salir. Cuando el usuario accede a la app, cualquier dato de Android que se muestre incluirá un saludo para que el usuario agregue un toque de personalización.
Descarga la app de muestra de las siguientes maneras:
Usa el siguiente comando para clonar el repositorio de GitHub desde la línea de comandos y cambia a la rama start
del repositorio:
$ git clone https://github.com/googlecodelabs/android-kotlin-login
Importante: Dado que integrarás la app para usar Firebase, esta app requiere cierta configuración a fin de que se pueda compilar y ejecutar. Lo harás en el próximo paso del codelab.
Paso 1: Crea un proyecto de Firebase
Antes de poder agregar Firebase a tu app para Android, debes crear un proyecto de Firebase y conectarlo a la app.
- En Firebase console, haz clic en Agregar proyecto.
- Selecciona o ingresa el Project name. Puedes asignarle un nombre a tu proyecto, pero elige un nombre que sea relevante para la app que compiles.
- Haga clic en Continuar.
- Puede omitir la configuración de Google Analytics y elegir la opción Ahora no.
- Haz clic en Crear proyecto para terminar de configurar el proyecto de Firebase.
Paso 2: Registra tu app con Firebase
Ahora que tienes un proyecto de Firebase, puedes agregarle tu app para Android.
- En el centro de la página de descripción general del proyecto en Firebase console, haz clic en el ícono de Android para iniciar el flujo de trabajo de configuración.
- Ingresa el ID de aplicación de tu app en el campo Nombre del paquete de Android. Asegúrate de ingresar el ID que usa tu app, ya que no podrás agregar ni modificar este valor después de registrarla en el proyecto de Firebase.
- A veces, nos referimos al ID de aplicación como un nombre de paquete.
- Encuentra este ID de aplicación en el archivo Gradle, generalmente
app/build.gradle
(ID de ejemplo:com.yourcompany.yourproject
). - Ingresa el certificado de firma de depuración SHA-1. Para generar esta clave, ingresa el siguiente comando en la terminal de la línea de comandos.
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
- Haz clic en Registrar app.
Paso 3: Agrega el archivo de configuración de Firebase a tu proyecto
Agrega el archivo de configuración de Firebase para Android a la app, como se indica a continuación:
- Haz clic en Descargar google-services.json a fin de obtener el archivo de configuración de Firebase para Android (
google-services.json
).
- Puedes volver a descargar el archivo de configuración de Firebase para Android cuando quieras.
- Asegúrate de que no se hayan agregado caracteres adicionales al archivo de configuración y que solo se deba llamar
google-services.json
- Traslada el archivo de configuración al directorio del módulo (nivel de app) de tu app.
Paso 4: Configura tu proyecto de Android para habilitar los productos de Firebase
- Agrega el complemento de google-services a tus archivos Gradle a fin de habilitar los productos de Firebase en tu app.
- Agrega reglas para incluir el complemento de Google Services en el archivo Gradle (
build.gradle
) de nivel de raíz (nivel de proyecto). Además, revisa que tengas el repositorio Maven de Google.
build.gradle
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
// ...
// Add the following line:
classpath 'com.google.gms:google-services:4.3.0' // Google Services plugin
}
}
allprojects {
// ...
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
// ...
}
}
- En el archivo Gradle (generalmente
app/build.gradle
) de tu módulo (a nivel de app), agrega una línea en la parte inferior del archivo.
app/build.gradle
apply plugin: 'com.android.application'
android {
// ...
}
// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin
Paso 4: Agrega la dependencia de Firebase
En este codelab, la razón principal para integrar Firebase es tener una manera de crear y administrar usuarios. Para ello, debes agregar una biblioteca de Firebase que te permita implementar el acceso.
- Agrega la siguiente dependencia al archivo
build.gradle (Module:app)
para que puedas usar el SDK en tu app. El SDK defirebase-auth
permite administrar usuarios autenticados de tu aplicación.
app/build.gradle:
implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
- Sincroniza tu proyecto con archivos de Gradle para asegurarte de que todas las dependencias estén disponibles en la app. Si no se te solicita, elige File > Sync Project with Gradle Files en Android Studio o desde la barra de herramientas.
Paso 5: Ejecuta la app e inspecciona el código
- Ejecuta la app en un emulador o dispositivo físico a fin de asegurarte de que el entorno esté configurado correctamente para comenzar a desarrollar.
Deberías ver que la pantalla principal muestra un dato curioso de Android y un botón de acceso en la esquina superior izquierda. Aún no se ha hecho nada presionando el botón de acceso.
En términos generales, esta es una app de actividad única con varios fragmentos. MainFragment
contiene toda la IU que verás en la siguiente pantalla. (Trabajarás con el LoginFragment
y el SettingsFragment
en un codelab de seguimiento).
- Familiarízate con el código. En particular, ten en cuenta lo siguiente:
FirebaseUserLiveData
es la clase que implementarás para observar el usuario actual de Firebase asociado con la app. Usarás la instanciaFirebaseAuth
como punto de entrada para obtener la información de este usuario en un paso posterior.- El
MainFragment
está vinculado alLoginViewModel
.LoginViewModel
es la clase que implementarás para usarFirebaseUserLiveData
a fin de crear una variableauthenticationState
. Con esta variableauthenticationState
,MainFragment
podrá observar el valor para actualizar la IU según corresponda.
En este paso, usarás Firebase console para configurar los métodos de autenticación que quieres que admita tu app. En este codelab, te enfocarás en permitir que los usuarios accedan con una dirección de correo electrónico que proporcionen o su Cuenta de Google.
- Ve a Firebase console. Nota: Si todavía estás en el flujo de trabajo de Agregar Firebase, haz clic en la X de la esquina superior izquierda para volver a la consola.
- Selecciona tu proyecto si aún no lo hiciste.
- Abre el panel de navegación izquierdo y selecciona Desarrollar &autenticación.
- Selecciona la pestaña Método de acceso en la barra de navegación superior.
- Haz clic en la fila Correo electrónico/Contraseña.
- En la ventana emergente, activa o desactiva el interruptor Habilitada y haz clic en Guardar.
- Haga clic en la fila Google.
- Active el interruptor Habilitada, ingrese una dirección de correo electrónico de asistencia del proyecto y haga clic en Guardar.
En esta tarea, implementarás la función de acceso para tus usuarios.
- Abre
MainFragment.kt
. - En el diseño de
MainFragment
, observa elauth_button
. Actualmente, no está configurado para controlar ninguna entrada del usuario. - En
onViewCreated(),
, agrega unonClickListener
aauth_button
para llamar alaunchSignInFlow()
.
MainFragment.kt
binding.authButton.setOnClickListener { launchSignInFlow() }
- Busca el método
launchSignInFlow()
enMainFragment.kt
. Actualmente contiene unaTODO
. - Completa la función
launchSignInFlow()
como se muestra a continuación.
MainFragment.kt
private fun launchSignInFlow() {
// Give users the option to sign in / register with their email or Google account.
// If users choose to register with their email,
// they will need to create a password as well.
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(), AuthUI.IdpConfig.GoogleBuilder().build()
// This is where you can provide more ways for users to register and
// sign in.
)
// Create and launch sign-in intent.
// We listen to the response of this activity with the
// SIGN_IN_REQUEST_CODE
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
MainFragment.SIGN_IN_REQUEST_CODE
)
}
Esto permite que los usuarios se registren y accedan con su dirección de correo electrónico o Cuenta de Google. Si el usuario decide registrarse con su dirección de correo electrónico, la combinación de correo electrónico y contraseña que cree será única para tu app. Esto significa que podrá acceder a ella con la combinación de dirección de correo electrónico y contraseña, pero no significa que también podrá acceder a cualquier otra app compatible con Firebase con las mismas credenciales.
- En
MainFragment.kt
, puedes escuchar el resultado del proceso de acceso mediante la implementación del métodoonActivityResult()
, como se muestra a continuación. Desde que comenzaste el proceso de acceso conSIGN_IN_REQUEST_CODE
, también puedes escuchar el resultado del proceso si filtras porSIGN_IN_REQUEST_CODE
y se devuelve aonActivityResult()
. Comienza por tener algunas instrucciones de registro para saber si el usuario accedió correctamente.
MainFragment.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == SIGN_IN_REQUEST_CODE) {
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
// User successfully signed in
Log.i(TAG, "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}!")
} else {
// Sign in failed. If response is null the user canceled the
// sign-in flow using the back button. Otherwise check
// response.getError().getErrorCode() and handle the error.
Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
}
}
}
Ahora, tu app debería poder administrar los registros y los usuarios.
- Ejecuta la app y verifica que, cuando se presione el botón Login, aparezca la pantalla de acceso.
- Ahora puedes acceder con tu dirección de correo electrónico y una contraseña o con tu Cuenta de Google.
- No habrá cambios en la IU después de acceder (implementarás la actualización de la IU en el siguiente paso), pero si todo funciona bien, deberías ver el mensaje de registro
Successfully signed in user ${your name}!
después de completar el flujo de registro. - También puedes ir a Firebase console y navegar a Desarrolla > Authentication > Users para verificar que la app ahora tenga un usuario registrado.
- Tenga en cuenta que cuando los usuarios crean una cuenta para su aplicación, esta se vincula específicamente solo a su aplicación, no a ninguna aplicación que utilice Firebase para la funcionalidad de acceso.
En esta tarea, implementarás la actualización de la IU en función del estado de autenticación. Cuando el usuario accede, puedes mostrar su nombre en la pantalla principal para personalizarla. También actualizarás el botón Acceder para que sea un botón Salir cuando el usuario haya accedido.
- Abre la clase
FirebaseUserLiveData.kt
, que ya se creó para ti. Lo primero que debes hacer es permitir que otras clases de la app sepan si un usuario accedió o salió. Sin embargo, la clase aún no hace nada, ya que el valor deLiveData
no se actualiza. - Dado que estás usando la biblioteca
FirebaseAuth
, puedes escuchar los cambios en el usuario conectado con la devolución de llamadaFirebaseUser.AuthStateListener
que se implementó como parte de la biblioteca de FirebaseUI. Esta devolución de llamada se activa cada vez que un usuario accede a tu app o sale de ella. - Ten en cuenta que
FirebaseUserLiveData.kt
define la variableauthStateListener
. Usarás esta variable para almacenar el valor deLiveData
. La variableauthStateListener
se creó para que puedas iniciar y detener correctamente los cambios en el estado de autenticación según el estado de tu aplicación. Por ejemplo, si el usuario coloca la app en segundo plano, esta debe dejar de detectar los cambios de estado de autenticación para evitar posibles fugas de memoria. - Actualiza
authStateListener
para que el valor de tuFirebaseUserLiveData
se corresponda con el usuario actual de Firebase.
FirebaseUserLiveData.kt
private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
value = firebaseAuth.currentUser
}
- Abre
LoginViewModel.kt
. - En
LoginViewModel.kt
, crea una variableauthenticationState
basada en el objetoFirebaseUserLiveData
que acabas de implementar. Al crear esta variableauthenticationState
, otras clases ahora pueden consultar si el usuario accedió o no a través deLoginViewModel
.
LoginViewModel.kt
val authenticationState = FirebaseUserLiveData().map { user ->
if (user != null) {
AuthenticationState.AUTHENTICATED
} else {
AuthenticationState.UNAUTHENTICATED
}
}
- Abrir
MainFragment.kt.
- En
observeAuthenticationState()
deMainFragment.kt
, puedes usar la variableauthenticationState
que acabas de agregar enLoginViewModel
y cambiar la IU según corresponda. Si un usuario accedió,authButton
debería mostrar Logout.
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
}
}
})
}
- Si el usuario accedió, también puedes personalizar el mensaje de bienvenida que ve mediante la función
getFactWithPersonalization()
proporcionada enMainFragment
.
MainFragment.kt
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
- Por último, si no hay un usuario que haya accedido (cuando
authenticationState
no esLoginViewModel.AuthenticationState.AUTHENTICATED
),auth_button
debería mostrar Acceder y, luego, iniciar la pantalla de acceso cuando se haga clic en ella. No debería haber personalización del mensaje que se muestra.
MainFragment.kt
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay
Una vez que hayas completado todos los pasos, tu método observeAuthenticationState()
final debería ser similar al siguiente código.
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
// TODO 1. Use the authenticationState variable you just added
// in LoginViewModel and change the UI accordingly.
when (authenticationState) {
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
binding.welcomeText.text = factToDisplay
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener {
launchSignInFlow()
}
}
}
})
}
- Ejecuta la app. La IU debería actualizarse en función de si un usuario accedió o no. Si todo funciona correctamente y accediste a tu cuenta, la pantalla principal ahora debería saludarte por tu nombre además de mostrar un dato de Android. Ahora, el botón Acceder también debería mostrar Salir.
En esta tarea, implementarás la función de salida.
Dado que la app permite que los usuarios accedan, también debe proporcionarles una forma de salir. A continuación, se muestra un ejemplo de cómo salir de la sesión de un usuario con una sola línea de código:
AuthUI.getInstance().signOut(requireContext())
- Abre
MainFragment.kt
. - En
observeAuthenticationState()
deMainFragment.kt
, agrega la lógica de cierre de sesión para queauth_button
funcione correctamente cuando haya un usuario conectado. El resultado final del método se parece al siguiente código:
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
AuthUI.getInstance().signOut(requireContext())
}
}
else -> {
binding.welcomeText.text = factToDisplay
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener {
launchSignInFlow()
}
}
}
})
}
- Ejecuta la app.
- Presiona el botón Salir y verifica que el usuario haya salido de su cuenta. Asimismo, el estado del botón cambia a Acceso.
Puedes encontrar la versión final de la app completa en https://github.com/googlecodelabs/android-kotlin-login.
En este codelab, aprendiste lo siguiente:
- Cómo agregar Firebase a tu proyecto al agregar las dependencias necesarias en tu archivo de Gradle y configurar el proyecto en Firebase console
- Cómo implementar el acceso para tu app con la biblioteca de FirebaseUI y especificar cómo quieres permitir que tus usuarios accedan. Ten en cuenta que cualquier cuenta que cree un usuario en tu app es específica solo de ella y no se comparte con todas las apps que usan Firebase para la funcionalidad de acceso.
- Cómo observar el estado actual de autenticación de tu app con
LiveData
- Cómo salir de la sesión de los usuarios
En este codelab, se trataron los aspectos básicos de cómo admitir el acceso de una app de Android.
En este codelab, permitiste que los usuarios se registraran y accedieran con su dirección de correo electrónico. Sin embargo, con la biblioteca FirebaseUI, también puedes admitir otros métodos de autenticación, como acceder con un número de teléfono. Para obtener más información sobre las funciones de la biblioteca de FirebaseUI y el uso de otras funcionalidades que proporciona, consulta los siguientes recursos:
- Documentación de autenticación de FirebaseUI
- Demostración de código de autenticación de FirebaseUI y código de muestra
Para obtener más información sobre las prácticas recomendadas de acceso, consulte los siguientes recursos:
Codelabs:
Documentación para desarrolladores de Android:
Videos:
Para obtener vínculos a otros codelabs de este curso, consulta la página de destino de Codelabs avanzados de Android en Kotlin.