Postado por Isai Damier, engenharia da plataforma do desenvolvedor Android (@isaidamier)

Kevin Chyn, biblioteca do Android

Curtis Belmonte, biblioteca do Android

Com o lançamento do Android 10 (API de nível 29), os desenvolvedores agora podem usar a API biométrica, parte da biblioteca AndroidX Biometric, para todas as necessidades de autenticação do usuário no dispositivo. A equipe da biblioteca e segurança do Android adicionou diversos recursos significativos à biblioteca AndroidX Biometric.Com isso, todo o comportamento biométrico do Android 10 é disponibilizado a todos os dispositivos que executam o Android 6.0 (API de nível 23) ou versões posteriores. A API é compatível com vários formatos de autenticação biométrica. Com ela, os desenvolvedores podem verificar com muito mais facilidade se determinado dispositivo tem sensores biométricos. Caso não haja nenhum sensor biométrico, a API permitirá que os desenvolvedores especifiquem se querem usar as credenciais do dispositivo nos aplicativos.

Os recursos não beneficiam apenas os desenvolvedores. Fabricantes de dispositivos e OEMs também têm bastante a comemorar. A biblioteca agora oferece uma API otimizada e padronizada para OEMs integrarem suporte a todos os tipos de sensores biométricos nos dispositivos. Além disso, a biblioteca tem suporte integrado para autenticação facial no Android 10. Assim, os fornecedores não precisam criar uma implementação personalizada.

Vamos rever o histórico?

A classe FingerprintManager foi introduzida no Android 6.0 (API de nível 23). Atualmente, e até o Android 9 (API de nível de 28), a API era compatível somente com sensores de impressão digital e sem IU. Os desenvolvedores precisavam criar uma IU de impressão digital própria.

Com base no feedback dos desenvolvedores, o Android 9 introduziu uma política da IU de impressão digital padronizada. O BiometricPrompt também foi introduzido para abranger mais sensores além da impressão digital. Além de fornecer uma IU segura e familiar para autenticação do usuário, isso permitiu que uma pequena superfície de API mantida pelos desenvolvedores acessasse a variedade de hardware biométrico disponível em dispositivos OEM. Agora, os OEMs podem personalizar a IU com os recursos e a iconografia necessários para expor novas biometrias, como contornos de sensores em exibição. Com isso, os desenvolvedores de aplicativos não precisam se preocupar em executar implementações personalizadas específicas de dispositivos para autenticação biométrica.

Ou seja, no Android 10, a equipe introduziu alguns recursos essenciais para transformar a API biométrica em um balcão único para a autenticação do usuário no aplicativo. Com o BiometricManager, os desenvolvedores podem verificar se um dispositivo é compatível com a autenticação biométrica. Além disso, o método setDeviceCredentialAllowed() foi adicionado para oferecer aos desenvolvedores a opção de usar o PIN, o padrão ou a senha de um dispositivo em vez da credencial biométrica, caso faça sentido para o aplicativo.

A equipe incluiu todos os recursos biométricos do Android 10 à dependência Gradle do androidx.biometric. Assim, uma interface única e consistente é disponibilizada até o Android 6.0 (API de nível 23).

Como funciona

A dependência Gradle do androidx.biometric é uma biblioteca de suporte para as classes Biometric da biblioteca Android. Na API 29 e versões posteriores, a biblioteca usa as classes em android.hardware.biometrics e FingerprintManager até a API 23 e a credencial de confirmação até a API 21. Devido à variedade de APIs, é altamente recomendado usar a biblioteca de suporte androidx, independentemente do nível de API executado no seu aplicativo.

Para usar a API biométrica no seu aplicativo, siga as etapas abaixo:

1. Adicione a dependência Gradle ao módulo do seu aplicativo

$biometric_version é a versão mais recente da biblioteca

def biometric_version= '1.0.0-rc02'
implementation "androidx.biometric:biometric:$biometric_version"

2. Verifique se o dispositivo é compatível com a autenticação biométrica

O BiometricPrompt precisa ser recriado todas as vezes que houver a criação de Activity/Fragment. Isso precisa ser feito no onCreate() ou onCreateView() para que BiometricPrompt.AuthenticationCallback possa começar a receber os callbacks adequadamente.

Para verificar se o dispositivo é compatível com a autenticação biométrica, adicione a lógica a seguir:

val biometricManager = BiometricManager.from(context)
if (biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS){
   // TODO: show in-app settings, make authentication calls.
}

3. Crie uma instância do BiometricPrompt

O construtor BiometricPrompt requer um Executor e um objeto AuthenticationCallback. Com o Executor, é possível especificar um thread que será usado para a execução dos callbacks.

O AuthenticationCallback tem três métodos:

  1. onAuthenticationSucceeded() é chamado quando o usuário foi autenticado usando uma credencial reconhecida pelo dispositivo.
  2. onAuthenticationError() é chamado quando ocorre um erro irrecuperável.
  3. onAuthenticationFailed() é chamado quando o usuário é rejeitado, por exemplo quando uma impressão digital não cadastrada é posicionada no sensor. No entanto, diferentemente do onAuthenticationError(), o usuário pode continuar tentando fazer a autenticação.

O snippet a seguir mostra uma maneira de implementar o Executor e como instanciar o BiometricPrompt:

private fun instanceOfBiometricPrompt(): BiometricPrompt {
   val executor = ContextCompat.getmainExecutor(context)

   val callback = object: BiometricPrompt.AuthenticationCallback() {
       override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
           super.onAuthenticationError(errorCode, errString)
           showMessage("$errorCode :: $errString")
       }

       override fun onAuthenticationFailed() {
           super.onAuthenticationFailed()
           showMessage("Authentication failed for an unknown reason")
       }

       override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
           super.onAuthenticationSucceeded(result)
           showMessage("Authentication was successful")
       }
   }

   val biometricPrompt = BiometricPrompt(context, executor, callback)
   return biometricPrompt
}

A instanciação do BiometricPrompt precisa ser concluída no início do ciclo de vida do fragmento ou da atividade (por exemplo,em onCreate ou onCreateView). Isso garante que a instância atual sempre receberá adequadamente os callbacks de autenticação.

4. Crie um objeto PromptInfo

Após ter um objeto BiometricPrompt, chame biometricPrompt.authenticate(promptInfo) para solicitar a autenticação ao usuário. Se o aplicativo exigir que o usuário autentique usando uma biometria forte ou precisar executar operações criptográficas no repositório de chaves, use authenticate(PromptInfo, CryptoObject).

Essa chamada mostrará a IU adequada ao usuário, com base no tipo da credencial biométrica usada para autenticação, como impressão digital, rosto ou íris. Como desenvolvedor, você não precisa saber qual o tipo de credencial é usado para autenticação, a API cuida disso tudo para você.

Essa chamada requer um objeto BiometricPrompt.PromptInfo. Um PromptInfo é onde você define o texto exibido na solicitação: como o título, subtítulo e a descrição. Sem um PromptInfo, não fica claro ao usuário final qual aplicativo está solicitando a credencial biométrica. Com o PromptInfo também é possível especificar se será permitido que dispositivos incompatíveis com a autenticação biométrica concedam acesso por meio das credenciais do dispositivo, como senha, PIN ou padrão usados para desbloquear o dispositivo.

Veja este exemplo de loop de declaração PromptInfo:

private fun getPromptInfo(): BiometricPrompt.PromptInfo {
   val promptInfo = BiometricPrompt.PromptInfo.Builder()
       .setTitle("My App's Authentication")
       .setSubtitle("Please login to get access")
       .setDescription("My App is using Android biometric authentication")
              .setDeviceCredentialAllowed(true)
       .build()
   return promptInfo
}

Para ações que requerem uma etapa de confirmação, como transações e pagamentos, recomendamos usar a opção padrão: setConfirmationRequired(true). Ela adicionará um botão de confirmação à IU, conforme exibido na Imagem 2.

Imagem 1. Exemplo de fluxo de autenticação facial usando BiometricPrompt com setConfirmationRequired(false).

Imagem 2. Exemplo de fluxo de autenticação facial usando BiometricPrompt com setConfirmationRequired(true) (comportamento padrão).

5. Solicite a autenticação do usuário

Agora que já realizou todas as etapas obrigatórias, solicite a autenticação do usuário.

val canAuthenticate = biometricManager.canAuthenticate()
if (canAuthenticate == BiometricManager.BIOMETRIC_SUCCESS) {
   biometricPrompt.authenticate(promptInfo)
} else {
   Log.d(TAG, "could not authenticate because: $canAuthenticate")
}

Está tudo pronto! Agora você pode executar a autenticação, usando credenciais biométricas, em qualquer dispositivo que opere no Android 6.0 (API de nível 23) ou versões posteriores.

Perspectivas futuras

Como o ecossistema continua a evoluir rapidamente, a equipe da biblioteca do Android pensa constantemente em formas de oferecer suporte a longo prazo para OEMs e desenvolvedores. Devido à IU com base no sistema consistente da biblioteca biométrica, os desenvolvedores não precisam se preocupar com requisitos específicos do dispositivo, e os usuários têm uma experiência mais confiável.

Será ótimo receber feedback de desenvolvedores e OEMs sobre como fortalecer, simplificar a utilização e melhorar o suporte de diversos casos de uso.

Para ver exemplos detalhados que exibem casos de uso adicionais e demonstram como você pode integrar essa biblioteca ao seu aplicativo, confira nosso repositório. Ele contém aplicativos de amostra funcionais que usam a biblioteca. Também é possível ler o guia do desenvolvedor associado e a referência da API para saber mais.