Cómo mostrar un diálogo de autenticación biométrica

Un método para proteger la información sensible o el contenido premium de tu app es solicitar autenticación biométrica, por ejemplo, reconocimiento facial o de huella digital. En esta guía, se explica cómo admitir flujos de acceso biométrico en tu app.

Comprueba que la autenticación biométrica esté disponible

Puedes comprobar si un dispositivo es compatible con la autenticación biométrica antes de invocar a BiometricPrompt con el método canAuthenticate() en la clase BiometricManager.

En el siguiente fragmento de código, se muestra cómo invocar este método:

Kotlin

    val biometricManager = BiometricManager.from(this)
    when (biometricManager.canAuthenticate()) {
        BiometricManager.BIOMETRIC_SUCCESS ->
            Log.d("App can authenticate using biometrics.")
        BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
            Log.e("No biometric features available on this device.")
        BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
            Log.e("Biometric features are currently unavailable.")
        BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
            Log.e("The user hasn't associated any biometric credentials " +
            "with their account.")
    }
    

Java

    BiometricManager biometricManager = BiometricManager.from(this);
    switch (biometricManager.canAuthenticate()) {
        case BiometricManager.BIOMETRIC_SUCCESS:
            Log.d("App can authenticate using biometrics.");
            break;
        case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
            Log.e("No biometric features available on this device.");
            break;
        case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
            Log.e("Biometric features are currently unavailable.");
            break;
        case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
            Log.e("The user hasn't associated any biometric credentials " +
                "with their account.");
            break;
    }
    

Muestra la solicitud de acceso

Para que el sistema le solicite al usuario que proporcione credenciales biométricas, usa la biblioteca biométrica. Este diálogo proporcionado por el sistema es igual en todas las apps que lo usan, lo que crea una experiencia del usuario más confiable. En la figura 1, aparece un ejemplo de este diálogo.

Captura de pantalla que muestra un diálogo
Figura 1: Diálogo del sistema que solicita autenticación biométrica

Para agregar autenticación biométrica a tu app con la biblioteca biométrica, sigue estos pasos:

  1. En el archivo app/build.gradle de tu app, agrega una dependencia para la biblioteca biométrica:

        dependencies {
            implementation 'androidx.biometric:biometric:1.0.0-beta01'
        }
        
  2. En la actividad o el fragmento que aloja el diálogo de acceso biométrico, muestra el diálogo con la lógica indicada en el siguiente fragmento de código:

    Kotlin

        private val executor = Executor { }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            // ...
            // Prompt appears when user clicks "Log in"
            val biometricLoginButton: Button = findViewById(R.id.biometric_login)
            biometricLoginButton.setOnClickListener { showBiometricPrompt() }
        }
    
        private fun showBiometricPrompt() {
            val promptInfo = BiometricPrompt.PromptInfo.Builder()
                    .setTitle("Biometric login for my app")
                    .setSubtitle("Log in using your biometric credential")
                    .setNegativeButtonText("Cancel")
                    .build()
    
            val biometricPrompt = BiometricPrompt(this, executor,
                    object : BiometricPrompt.AuthenticationCallback() {
                override fun onAuthenticationError(errorCode: Int,
                        errString: CharSequence) {
                    super.onAuthenticationError(errorCode, errString)
                    Toast.makeText(applicationContext,
                        "Authentication error: $errString", Toast.LENGTH_SHORT)
                        .show()
                }
    
                override fun onAuthenticationSucceeded(
                        result: BiometricPrompt.AuthenticationResult) {
                    super.onAuthenticationSucceeded(result)
                    val authenticatedCryptoObject: BiometricPrompt.CryptoObject =
                            result.getCryptoObject()
                    // User has verified the signature, cipher, or message
                    // authentication code (MAC) associated with the crypto object,
                    // so you can use it in your app's crypto-driven workflows.
                }
    
                override fun onAuthenticationFailed() {
                    super.onAuthenticationFailed()
                    Toast.makeText(applicationContext, "Authentication failed",
                        Toast.LENGTH_SHORT)
                        .show()
                }
            })
    
            // Displays the "log in" prompt.
            biometricPrompt.authenticate(promptInfo)
        }
        

    Java

        private Handler handler = new Handler();
    
        private Executor executor = new Executor() {
            @Override
            public void execute(Runnable command) {
                handler.post(command);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // ...
            // Prompt appears when user clicks "Log in"
            Button biometricLoginButton = findViewById(R.id.biometric_login);
            biometricLoginButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    showBiometricPrompt();
                }
            });
        }
    
        private void showBiometricPrompt() {
            BiometricPrompt.PromptInfo promptInfo =
                    new BiometricPrompt.PromptInfo.Builder()
                    .setTitle("Biometric login for my app")
                    .setSubtitle("Log in using your biometric credential")
                    .setNegativeButtonText("Cancel")
                    .build();
    
            BiometricPrompt biometricPrompt = new BiometricPrompt(MainActivity.this,
                    executor, new BiometricPrompt.AuthenticationCallback() {
                @Override
                public void onAuthenticationError(int errorCode,
                        @NonNull CharSequence errString) {
                    super.onAuthenticationError(errorCode, errString);
                    Toast.makeText(getApplicationContext(),
                        "Authentication error: " + errString, Toast.LENGTH_SHORT)
                        .show();
                }
    
                @Override
                public void onAuthenticationSucceeded(
                        @NonNull BiometricPrompt.AuthenticationResult result) {
                    super.onAuthenticationSucceeded(result);
                    BiometricPrompt.CryptoObject authenticatedCryptoObject =
                            result.getCryptoObject();
                    // User has verified the signature, cipher, or message
                    // authentication code (MAC) associated with the crypto object,
                    // so you can use it in your app's crypto-driven workflows.
                }
    
                @Override
                public void onAuthenticationFailed() {
                    super.onAuthenticationFailed();
                    Toast.makeText(getApplicationContext(), "Authentication failed",
                        Toast.LENGTH_SHORT)
                        .show();
                }
            });
    
            // Displays the "log in" prompt.
            biometricPrompt.authenticate(promptInfo);
        }
        

Autentica sin acción explícita del usuario

De manera predeterminada, el sistema requiere que los usuarios realicen una acción específica, como presionar un botón, una vez que se aceptan las credenciales biométricas. Esta configuración es la que se prefiere si tu app muestra el diálogo para confirmar una acción sensible o de alto riesgo, como realizar una compra.

Si tu app muestra un diálogo de autenticación biométrica para una acción de menor riesgo, sin embargo, puedes proporcionar una sugerencia para el sistema que indique que no es necesario que el sistema realice la acción para autenticarse. Esta pista puede permitir al usuario ver el contenido en tu app más rápidamente después de volver a autenticarse mediante una modalidad pasiva, como el reconocimiento facial o de iris. Para proporcionar esta pista, pasa false al método setConfirmationRequired().

La figura 2 muestra dos versiones del mismo diálogo. Una versión requiere una acción del usuario explícita, mientras que la otra no.

Captura de pantalla del diálogo Captura de pantalla del diálogo
Figura 2: Autenticación facial sin confirmación del usuario (arriba) y con confirmación del usuario (abajo)

En el siguiente fragmento de código, se muestra cómo presentar un diálogo que no requiere de una acción explícita del usuario para completar el proceso de autenticación:

Kotlin

    // Allows user to authenticate without performing an action, such as pressing a
    // button, after their biometric credential is accepted.
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric login for my app")
            .setSubtitle("Log in using your biometric credential")
            .setNegativeButtonText("Cancel")
            .setConfirmationRequired(false)
            .build()
    

Java

    // Allows user to authenticate without performing an action, such as pressing a
    // button, after their biometric credential is accepted.
    BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric login for my app")
            .setSubtitle("Log in using your biometric credential")
            .setNegativeButtonText("Cancel")
            .setConfirmationRequired(false)
            .build();
    

Admite el resguardo de credenciales no biométricas

Si el usuario no puede autenticarse con sus credenciales biométricas, puedes permitirle que lo haga con el PIN, el patrón o la contraseña de su dispositivo. Para ello, debe pasar el objeto true al método setDeviceCredentialAllowed(). En el siguiente fragmento de código, se muestra cómo proporcionar compatibilidad con ese resguardo:

Kotlin

    // Allows user to authenticate using a PIN, pattern, or password.
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric login for my app")
            .setSubtitle("Log in using your biometric credential")
            .setNegativeButtonText("Cancel")
            .setDeviceCredentialAllowed(true)
            .build()
    

Java

    // Allows user to authenticate using a PIN, pattern, or password.
    BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric login for my app")
            .setSubtitle("Log in using your biometric credential")
            .setNegativeButtonText("Cancel")
            .setDeviceCredentialAllowed(true)
            .build();