Hace unas semanas comencé a desarrollar una app móvil para un proyecto personal, al llegar a la tarea de autenticar a los usuarios considere la opción de integrar Firebase a mi proyecto, una de sus soluciones es Firebase Auth permite implementar la autenticación del usuario utilizando algunos de los proveedores populares como google, facebook, microsoft, twitter sin tener que crear el backend de autenticación nosotros mismos.
Esta solución cumple con lo que requiero en este caso:
- Acelerar el desarrollo de la app, avanzar en otras funcionalidades delegando a firebase la responsabilidad de autenticación.
- Firebase se encarga del proceso de autenticación y nosotros solo definimos los flujos y proveedores a utilizar.
- La mayor parte de dispositivos de mis usuarios objetivo utilizan android con una cuenta de google.
- Familiarizarme con Firebase en el desarrollo móvil
Integración de Firebase Auth en kotlin, a continuación te comparto algunos detalles sobre el proyecto:
- Android Studio Giraffe | 2022.3.1 Patch 3
- Aplicación desarrollada en kotlin
- Configurar autenticación con Google provider
Procedimiento para integrar Firebase Auth
Crear nuevo proyecto
Para comenzar crea un nuevo proyecto en android studio utilizando la plantilla Empty Activity.
En este punto debe ser suficiente con mantener la configuración del nuevo proyecto con los valores por defecto asignados por el asistente de android studio.
Agregar Firebase al proyecto
Antes de comenzar debemos agregar firebase a nuestro proyecto, al agregarlo estamos enlazando nuestra aplicación a un proyecto creado en firebase donde podremos encontrar algunas métricas y opciones de configuración para nuestra app.
Puedes apoyarte del siguiente enlace Add Firebase to your Android project es parte de la documentación oficial de firebase, en mí caso, utilice la opción 1 me resulto más entendible y me ayudo con el tema de las dependencias.
Agregar dependencias de Firebase al proyecto
Una vez creado el proyecto y agregado firebase, continuaremos agregando las dependencias para integrar Firebase Auth y la dependencia necesaria para utilizar Google como proveedor de autenticación.
Las dependencias se agregan a nivel de app en el archivo build.gradle.kts (Module:app) puedes consultar el enlace del punto anterior donde al agregar firebase al proyecto se pueden observar un par de líneas comentas donde una de ellas es la de Firebase Auth y es la que utilizaremos, puedes consultar este enlace para apoyarte, también es parte de la documentación oficial que hasta ahora resulta muy útil.
No olvides sincronizar gradle dando clic en Sync Now ubicado en la parte superior derecha, sino lo sincronizas las dependencias no serán agregadas al proyecto.
Diseño de UI para utilizar Google provider
Para comenzar a usar google como proveedor de autenticación podemos agregar un botón predefinido con el estilo de google para iniciar sesión con una cuenta gmail configurada en el dispositivo.
app > res > layout > activity_main.xml
<com.google.android.gms.common.SignInButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:id="@+id/btnGoogleSignIn"
/>
El código anterior muestra la definición simple de un botón predefinido que podemos usar para integrar en nuestro diseño y desplegar un activity emergente donde podremos seleccionar la cuenta con la que queramos autenticarnos, usuarios estándar podremos tener una sola cuenta gmail en nuestro teléfono celular o tablet pero existe quien pueda tener más de una, en esta pantalla deberá seleccionar la cuenta que prefiera usar para autenticarse en la aplicación.
Nota. El botón de google a veces se muestra en la pantalla de diseño de android studio y en ocasiones no se muestra visualmente pero si esta presente dentro del diseño, aún no conozco mucho android studio y su ambiente pero cuando ejecutes la app en tu celular o tablet podrás observar mejor el botón, si descubro el porque actualizare la información.
Autenticación y consulta de datos
A partir de aquí comenzaremos a escribir código
Si ya creaste el proyecto en android studio podrás observar en el archivo MainActivity.kt dos métodos: onStart() y onCreate()
- onStart – Evento del activity cada que se pinta la UI en pantalla.
- onCreate – Evento del activity que se ejecuta una sola vez durante el ciclo de vida del activity
Nos concentraremos en onCreate para pode inicializar firebase e inicializar el botón de inicio de sesión de google con el inicio del flujo de autenticación.
/* my code */
auth = FirebaseAuth.getInstance()
btnGoogleSignIn = findViewById(R.id.btnGoogleSignIn)
btnGoogleSignIn.setOnClickListener {
startSignIn()
}
startSignIn
Esté método inicializa el intent con google como proveedor de autenticación para logearse utilizando la cuenta de google registrada en el dispositivo.
Configuraremos algunas opciones relevantes a través de GoogleSignInOptions:
- Usaremos la autenticación por defecto con DEFAULT_SIGN_IN
- Solicitar un token Id para los usuarios, para esto será necesario pasarle nuestro web client id asignado cuando habilitamos la autenticación con google a nuestra app en firebase console.
- Solicitar email del usuario
Definiremos un GoogleSignIn.getClient() y le pasaremos como parámetro las opciones que ya configuramos.
Finalmente usaremos el cliente para obtener y lanzar intent.
private fun startSignIn(){
try {
val googleSignOptions = GoogleSignInOptions .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.google_web_client_id))
.requestEmail()
.requestProfile()
.build()
val googleSignInClient = GoogleSignIn.getClient(this, googleSignOptions)
googleSignInClient.signOut()
val signInIntent = googleSignInClient.signInIntent
signInLauncher.launch(signInIntent)
} catch (e: Exception){
val msg = e.message
}
}
En este punto si ejecutas la aplicación en tu dispositivo móvil deberá lanzar la aplicación y mostrarte el botón que definimos, dale tap y observa una pantalla donde podrás elegir una cuenta de google proponiéndote las cuentas que tengas configuradas en tu dispositivo.
Te recomiendo que te detengas a ejecutar y hacer pruebas para familiarizarte con el ciclo de vida de la aplicación y el momento en que se crean los elementos porque ahora necesitaremos capturar el resultado del intent (seleccionar la cuenta).
Nota: Siguiendo algunos ejemplos de la web y de youtube me tope con un problema que al parecer es por la versión de la lib o por la migración de algunas características entre java y kotlin esa fue mi conclusión aún que aún no lo puedo asegurar pero pude continuar buscando una alternativa.
Impedimentos
El error se daba al intentar utilizar startActivityForResult para capturar el resultado del intent de google, la alternativa fue utilizar un ActivityResultLauncher para capturar el resultado y procesar los datos de esa pantalla emergente donde el usuario se autentica.
/* Captura el resultado del Activity de autenticación de google provider */
private val signInLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
{ result: ActivityResult ->
this.onSignInResult(result)
})
onSignInResult
Procesa el resultado del activity de google provider login.
En este punto podemos evaluar la respuesta del intent y si todo a salido bien hasta ahora podemos obtener la cuenta del usuario, esta cuenta es la información del usuario que podemos consultar a través de google, y como un segundo paso ahora tenemos que autenticarnos en firebase, podría entenderse como que el flujo de autenticación internamente requiere que nos autentiquemos primero con el proveedor y después en firebase.
private fun onSignInResult(result: ActivityResult) {
if (result.resultCode == RESULT_OK) {
// Autenticación en google, exitosa
var account: GoogleSignInAccount? = googleProviderAuth(result.data)
if(account != null){
googleFirebaseAuth(account)
}
} else {
/* Autenticación fallida. Cancelada por el usuario o uso regresar */
}
}
googleProviderAuth
Procesa intent (respuesta) de autenticación firebase, si el proceso es exitoso obtendremos la cuenta de google del usuario de donde podremos consultar algunos datos pero el que nos interesa para este flujo es el token id..
private fun googleProviderAuth(intentResult: Intent?): GoogleSignInAccount? {
//1. Autenticación en google y despues firebase
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(intentResult)
try {
/* google account*/
val account = task.getResult(ApiException::class.java)
return account
} catch (ex: ApiException){
val msg = ex.message
//throw Exception()
}
return null
}
googleFirebaseAuth,
Definición del proceso de autenticación en firebase usando el token id obtenido a través del proveedor de autenticación de google.
private fun googleFirebaseAuth(account: GoogleSignInAccount){
// Firebase recibe las credenciales del usuario logeado en google
val credential: AuthCredential = GoogleAuthProvider.getCredential(account.idToken, null)
auth.signInWithCredential(credential).addOnCompleteListener {
if (it.isSuccessful) {
val usr: FirebaseUser? = it.result.user
Toast.makeText(this, "Login exitoso" + it.result?.user?.email ?: "NoEmail", Toast.LENGTH_LONG).show()
//navigateToActivityHome()
} else {
Toast.makeText(this, "Login fallido", Toast.LENGTH_LONG).show()
}
}
}
En este ultimo paso podrás observar el punto final del flujo de autenticación y agregar el código correspondiente a tu flujo ya sea redirigir a otro activity, obtener la información del usuario y registrarla en algún lugar, o lanzar nuevos elementos en la UI personalizándolos con los datos del usuario.
Gracias por llegar hasta el final, espero mis notas te sean de ayuda en el camino!