Exibir uma caixa de diálogo para autenticação biométrica

Um método de proteger informações confidenciais ou conteúdo premium no seu app é solicitar autenticação biométrica, usando reconhecimento facial ou de impressão digital. Este guia explica como fazer com que seu app seja compatível com o login por biometria.

Verificar se a autenticação biométrica está disponível

É possível verificar se um dispositivo é compatível com a autenticação biométrica antes de invocar BiometricPrompt, usando o método canAuthenticate() na classe BiometricManager.

O snippet de código a seguir mostra como invocar esse 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;
    }
    

Exibir a solicitação de login

Para exibir uma solicitação do sistema solicitando que o usuário informe credenciais biométricas, use a biblioteca Biometric. Essa caixa de diálogo do sistema é consistente em todos os apps que a utilizam, criando uma experiência mais confiável para o usuário. Um exemplo de caixa de diálogo é apresentado na Figura 1.

Captura de tela mostrando a caixa de diálogo
Figura 1. Caixa de diálogo do sistema solicitando a autenticação biométrica.

Para adicionar a autenticação biométrica ao app usando a biblioteca Biometric, siga as etapas a seguir:

  1. No arquivo app/build.gradle do app, adicione uma dependência para a biblioteca Biometric:

        dependencies {
            implementation 'androidx.biometric:biometric:1.0.0-beta01'
        }
        
  2. Na atividade ou fragmento que hospeda a caixa de diálogo para login por biometria, mostre a caixa de diálogo usando a lógica apresentada no snippet de código a seguir:

    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);
        }
        

Autenticar sem ação explícita do usuário

Por padrão, depois de aceitar as credenciais biométricas, o sistema solicita que o usuário realize uma ação específica, como apertar um botão. É preferível usar essa configuração se seu app exibe caixas de diálogo para confirmar ações confidenciais ou de alto risco, como uma compra.

No entanto, se seu app exibe uma caixa de diálogo para autenticação biométrica para ações de risco mais baixo, é possível dar uma dica para o sistema, indicando que o usuário não precisa realizar a ação para se autenticar. Essa dica pode permitir que o usuário visualize o conteúdo no app de forma mais rápida depois de repetir a autenticação usando uma modalidade passiva, como reconhecimento facial ou de íris. Para dar essa dica, passe false para o método setConfirmationRequired().

A figura 2 mostra duas versões da mesma caixa de diálogo. Uma delas exige uma ação explícita do usuário, enquanto a outra não.

Captura de tela da caixa de diálogo Captura de tela da caixa de diálogo
Figura 2. Autenticação facial sem confirmação do usuário (acima) e com confirmação do usuário (abaixo).

O snippet de código a seguir mostra como apresentar uma caixa de diálogo que não exige uma ação explícita do usuário para realizar o processo de autenticação:

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();
    

Permitir fallback para credenciais não biométricas

Se o usuário não conseguir realizar a autenticação usando as credenciais biométricas, você poderá permitir que ele use o PIN, o padrão ou a senha do dispositivo, passando true para o método setDeviceCredentialAllowed(). O snippet de código a seguir mostra como oferecer compatibilidade com esse fallback:

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();