显示生物识别身份验证对话框

要保护您的应用中的敏感信息或付费内容,一种方法是请求生物识别身份验证,例如使用人脸识别或指纹识别。本指南介绍了如何在您的应用中支持生物识别登录流程。

检查生物识别身份验证是否可用

您可以通过在 BiometricManager 类中使用 canAuthenticate() 方法,在调用 BiometricPrompt 之前检查设备是否支持生物识别身份验证。

以下代码段演示了如何调用此方法:

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

显示登录提示

要显示请求用户提供生物识别凭据的系统提示,请使用 Biometric 库。这个由系统提供的对话框在使用它的各个应用之间均保持一致,从而打造更值得信赖的用户体验。图 1 中显示了一个示例对话框。

显示对话框的屏幕截图
图 1 请求生物识别身份验证的系统对话框

要使用 Biometric 库向您的应用添加生物识别身份验证,请完成下列步骤:

  1. 在应用的 app/build.gradle 文件中,添加 Biometric 库的依赖项:

        dependencies {
            implementation 'androidx.biometric:biometric:1.0.0-beta01'
        }
        
  2. 在托管生物识别登录对话框的 Activity 或 Fragment 中,使用以下代码段中所示的逻辑来显示对话框:

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

无需显式用户操作的身份验证

默认情况下,在接受了用户的生物识别凭据后,系统会要求用户执行特定的操作,例如按某个按钮。如果您的应用显示对话框来确认敏感或高风险的操作(例如进行购买交易),那么这是首选的配置。

不过,如果您的应用针对较低风险的操作显示生物识别身份验证对话框,您可以向系统提供提示,表明用户无需执行操作以进行验证身份。此提示能够让用户在使用被动模式(如人脸识别或虹膜识别)重新验证身份后,更加快速地查看您的应用中的内容。要提供此提示,请将 false 传递到 setConfirmationRequired() 方法中。

图 2 展示了同一对话框的两个版本。一个版本需要显式用户操作,另一个版本则不需要。

对话框的屏幕截图 对话框的屏幕截图
图 2. 无需用户确认(上)和需要用户确认(下)的人脸识别身份验证

以下代码段展示了如何显示需要显式用户操作来完成身份验证流程的对话框:

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

允许回退到非生物识别凭据

如果用户无法使用生物识别凭据进行身份验证,您可以通过将 true 传递到 setDeviceCredentialAllowed() 方法中,允许他们利用设备 PIN 码、图案或密码进行身份验证。以下代码段展示了如何提供这种回退支持:

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