Usa el cliente de acceso con un toque para solicitarle permiso al usuario para recuperar una de las credenciales que usó anteriormente para acceder a tu app. Estas credenciales pueden ser una Cuenta de Google o una combinación de nombre de usuario y contraseña que guardó con Google mediante Chrome, la función Autocompletar de Android o Smart Lock para contraseñas.
Cuando se recuperan las credenciales de forma correcta, puedes usarlas para que el usuario acceda a tu app sin inconvenientes.
Si el usuario no guardó ninguna credencial, no se presentará ninguna IU y podrás proporcionar la experiencia normal de salida.
¿Dónde debo usar el acceso con One Tap?
Si tu app requiere que los usuarios accedan, muestra la IU de One Tap en la pantalla de acceso. Esto puede ser útil incluso si ya tienes un botón "Acceder con Google", ya que la IU de One Tap se puede configurar para mostrar solo las credenciales que el usuario usó anteriormente para acceder. Esto puede ser un recordatorio para los usuarios que acceden con poca frecuencia de cómo lo hicieron la última vez y evitar que creen cuentas nuevas con tu app por accidente.
Si el acceso es opcional para tu app, considera usar el acceso con One Tap en cualquier pantalla que tenga una experiencia mejorada cuando se accede. Por ejemplo, si los usuarios pueden explorar contenido con tu app sin haber accedido, pero solo pueden publicar comentarios o agregar artículos a un carrito de compras después de acceder, ese sería un contexto adecuado para el acceso con un toque.
Las apps con acceso opcional también deben usar el acceso con One Tap en sus pantallas de acceso por los motivos mencionados anteriormente.
Antes de comenzar
- Configura tu proyecto de la Consola de APIs de Google y tu proyecto de Android como se describe en Comienza a usar el Acceso con un toque.
- Si admites el acceso con contraseña, optimiza tu app para el autocompletado (o usa Smart Lock para contraseñas) para que los usuarios puedan guardar sus credenciales de contraseña después de acceder.
1. Configura el cliente de acceso con One Tap
Puedes configurar el cliente de acceso con One Tap para que los usuarios accedan con contraseñas o Cuentas de Google guardadas. (Se recomienda admitir ambos para permitir la creación de cuentas con un solo toque para los usuarios nuevos y el acceso automático o con un solo toque para tantos usuarios recurrentes como sea posible).
Si tu app usa el acceso con contraseña, usa setPasswordRequestOptions()
para habilitar las solicitudes de credenciales de contraseña.
Si tu app usa Acceso con Google, usa setGoogleIdTokenRequestOptions()
para habilitar y configurar las solicitudes de tokens de ID de Google:
Establece el ID de cliente del servidor en el ID que creaste en la consola de APIs de Google. Ten en cuenta que este es el ID de cliente de tu servidor, no el de Android.
Configura el cliente para que filtre por cuentas autorizadas. Cuando habilitas esta opción, el cliente de One Tap solo les solicita a los usuarios que accedan a tu app con las Cuentas de Google que ya usaron anteriormente. Esto puede ayudar a los usuarios a acceder de forma correcta cuando no saben si ya tienen una cuenta o qué Cuenta de Google usaron, y evita que los usuarios creen cuentas nuevas por accidente con tu app.
Si quieres que los usuarios accedan automáticamente cuando eso sea posible, habilita la función con
setAutoSelectEnabled()
. El acceso automático es posible cuando se cumplen los siguientes criterios:- El usuario tiene exactamente una credencial guardada para tu app. Es decir, una contraseña guardada o una Cuenta de Google guardada.
- El usuario no inhabilitó el acceso automático en la configuración de su Cuenta de Google.
Si bien es opcional, te recomendamos que consideres usar un nonce para mejorar la seguridad de acceso y evitar ataques de repetición. Usa setNonce para incluir un nonce en cada solicitud. Consulta la sección Obtener un nonce de SafetyNet para obtener sugerencias y detalles adicionales sobre cómo generar un nonce.
Java
public class YourActivity extends AppCompatActivity { // ... private SignInClient oneTapClient; private BeginSignInRequest signInRequest; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); oneTapClient = Identity.getSignInClient(this); signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.default_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build(); // ... } // ... }
Kotlin
class YourActivity : AppCompatActivity() { // ... private lateinit var oneTapClient: SignInClient private lateinit var signInRequest: BeginSignInRequest override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) oneTapClient = Identity.getSignInClient(this) signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions( BeginSignInRequest.GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.your_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build() // ... } // ... }
2. Cómo verificar si un usuario accedió a su cuenta
Si un usuario que accedió a su cuenta o que salió de ella puede usar tu actividad, verifica su estado antes de mostrar la IU de acceso con un toque.
También debes hacer un seguimiento de si el usuario ya rechazó usar el acceso con un toque. Para ello, cierra el mensaje o presiona fuera de él. Esto puede ser tan simple como una propiedad booleana de tu actividad. (consulta Cómo dejar de mostrar la IU de One Tap a continuación).
3. Cómo mostrar la IU de acceso con One Tap
Si el usuario no accedió y aún no rechazó usar el acceso con un toque, llama al método beginSignIn()
del objeto cliente y adjunta objetos de escucha al Task
que devuelve. Por lo general, las apps hacen esto en el método onCreate()
de la actividad o después de las transiciones de pantalla cuando usan una arquitectura de una sola actividad.
El cliente de One Tap llamará al objeto de escucha de éxito si el usuario tiene credenciales
guardadas para tu app. En el objeto de escucha de éxito, obtén el intent pendiente del
resultado Task
y pásalo a startIntentSenderForResult()
para iniciar la IU de acceso de One Tap.
Si el usuario no tiene credenciales guardadas, el cliente de One Tap llamará al objeto de escucha de fallas. En este caso, no es necesario realizar ninguna acción: puedes seguir presentando la experiencia de la app sin haber accedido a la cuenta. Sin embargo, si admites el registro con un toque, puedes iniciar ese flujo aquí para obtener una experiencia de creación de cuenta sin problemas. Consulta Cómo crear cuentas nuevas con un solo toque.
Java
oneTapClient.beginSignIn(signUpRequest)
.addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
@Override
public void onSuccess(BeginSignInResult result) {
try {
startIntentSenderForResult(
result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.getLocalizedMessage());
}
});
Kotlin
oneTapClient.beginSignIn(signInRequest)
.addOnSuccessListener(this) { result ->
try {
startIntentSenderForResult(
result.pendingIntent.intentSender, REQ_ONE_TAP,
null, 0, 0, 0, null)
} catch (e: IntentSender.SendIntentException) {
Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
.addOnFailureListener(this) { e ->
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.localizedMessage)
}
4. Controla la respuesta del usuario
La respuesta del usuario al mensaje de acceso con un toque se informará a tu app con el método onActivityResult()
de tu actividad. Si el usuario eligió acceder,
el resultado será una credencial guardada. Si el usuario rechazó acceder, ya sea que cierre la IU de One Tap o presione fuera de ella, el resultado se mostrará con el código RESULT_CANCELED
. Tu app debe controlar ambas posibilidades.
Cómo acceder con las credenciales recuperadas
Si el usuario eligió compartir credenciales con tu app, puedes recuperarlas pasando los datos del intent de onActivityResult()
al método getSignInCredentialFromIntent()
del cliente de One Tap. La credencial tendrá una propiedad googleIdToken
no nula si el usuario compartió una credencial de Cuenta de Google con tu app, o una propiedad password
no nula si el usuario compartió una contraseña guardada.
Usa la credencial para autenticarte con el backend de tu app.
- Si se recuperó un par de nombre de usuario y contraseña, úsalo para acceder de la misma manera que lo harías si el usuario los hubiera proporcionado de forma manual.
Si se recuperaron las credenciales de la Cuenta de Google, usa el token de ID para autenticarte con tu backend. Si elegiste usar un nonce para evitar ataques de repetición, verifica el valor de la respuesta en tu servidor de backend. Consulta Cómo autenticar con un backend mediante tokens de ID.
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data); String idToken = credential.getGoogleIdToken(); String username = credential.getId(); String password = credential.getPassword(); if (idToken != null) { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token."); } else if (password != null) { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password."); } } catch (ApiException e) { // ... } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { val credential = oneTapClient.getSignInCredentialFromIntent(data) val idToken = credential.googleIdToken val username = credential.id val password = credential.password when { idToken != null -> { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token.") } password != null -> { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password.") } else -> { // Shouldn't happen. Log.d(TAG, "No ID token or password!") } } } catch (e: ApiException) { // ... } } } } // ... }
Deja de mostrar la IU de One Tap
Si el usuario rechazó acceder, la llamada a getSignInCredentialFromIntent()
arrojará un ApiException
con un código de estado CommonStatusCodes.CANCELED
.
Cuando esto suceda, debes inhabilitar temporalmente la IU de acceso con un toque para no molestar a los usuarios con mensajes repetidos. En el siguiente ejemplo, se logra esto configurando una propiedad en la actividad, que se usa para determinar si se le ofrece al usuario el acceso con un toque. Sin embargo, también puedes guardar un valor en SharedPreferences
o usar algún otro método.
Es importante implementar tu propio límite de frecuencia de las indicaciones de acceso con un toque. Si no lo haces y un usuario cancela varias indicaciones seguidas, el cliente de One Tap no le hará preguntas al usuario durante las próximas 24 horas.
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { // ... } catch (ApiException e) { switch (e.getStatusCode()) { case CommonStatusCodes.CANCELED: Log.d(TAG, "One-tap dialog was closed."); // Don't re-prompt the user. showOneTapUI = false; break; case CommonStatusCodes.NETWORK_ERROR: Log.d(TAG, "One-tap encountered a network error."); // Try again or just ignore. break; default: Log.d(TAG, "Couldn't get credential from result." + e.getLocalizedMessage()); break; } } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { // ... } catch (e: ApiException) { when (e.statusCode) { CommonStatusCodes.CANCELED -> { Log.d(TAG, "One-tap dialog was closed.") // Don't re-prompt the user. showOneTapUI = false } CommonStatusCodes.NETWORK_ERROR -> { Log.d(TAG, "One-tap encountered a network error.") // Try again or just ignore. } else -> { Log.d(TAG, "Couldn't get credential from result." + " (${e.localizedMessage})") } } } } } } // ... }
5. Controla la salida
Cuando un usuario salga de tu app, llama al método signOut()
del cliente de One Tap.
Llamar a signOut()
inhabilita el acceso automático hasta que el usuario vuelva a acceder.
Incluso si no usas el acceso automático, este paso es importante porque garantiza que, cuando los usuarios salgan de tu app, el estado de autenticación de las APIs de los Servicios de Play que uses también se restablezca.
Próximos pasos
Si configuraste el cliente de One Tap para recuperar credenciales de Google, tu app ahora puede obtener tokens de ID de Google que representan las Cuentas de Google de tus usuarios. Obtén información para usar estos tokens en el backend.
Si admites el Acceso con Google, también puedes usar el cliente One Tap para agregar flujos de creación de cuentas sin inconvenientes a tu app.