Android 指纹验证

Posted Android-kongqw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 指纹验证相关的知识,希望对你有一定的参考价值。

android 指纹验证

本篇记录一下在Android上做指纹校验的过程。在某些敏感场景,可以通过指纹验证操作者是否是设备主人。

本篇使用的androidx 下的Biometric来实现的,FingerprintManagerCompat已经被官方标记过时,就不过多描述了。

加入依赖

implementation 'androidx.biometric:biometric:1.1.0'

检查是否支持指纹验证

检查设备硬件是否支持或者是否设置了指纹(至少一个或更多)

BiometricManager.BIOMETRIC_SUCCESS == BiometricManager.from(context).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)

进行验证

核心类BiometricPrompt,通过authenticate方法启动验证。

  1. 创建一个BiometricPrompt
 mBiometricPrompt = BiometricPrompt(`activity or fragment`, `BiometricPrompt.AuthenticationCallback`)
  1. 进行验证
mBiometricPrompt?.authenticate(`BiometricPrompt.PromptInfo`)

上面伪代码中BiometricPrompt的第一个参数,为Activity或Fragment,第二个参数为识别验证的回调,代码如下:

/**
 * A collection of methods that may be invoked by @link BiometricPrompt during authentication.
 */
public abstract static class AuthenticationCallback 
    /**
     * Called when an unrecoverable error has been encountered and authentication has stopped.
     *
     * <p>After this method is called, no further events will be sent for the current
     * authentication session.
     *
     * @param errorCode An integer ID associated with the error.
     * @param errString A human-readable string that describes the error.
     */
    public void onAuthenticationError(@AuthenticationError int errorCode, @NonNull CharSequence errString) 

    /**
     * Called when a biometric (e.g. fingerprint, face, etc.) is recognized, indicating that the
     * user has successfully authenticated.
     *
     * <p>After this method is called, no further events will be sent for the current
     * authentication session.
     *
     * @param result An object containing authentication-related data.
     */
    public void onAuthenticationSucceeded(@NonNull AuthenticationResult result) 

    /**
     * Called when a biometric (e.g. fingerprint, face, etc.) is presented but not recognized as
     * belonging to the user.
     */
    public void onAuthenticationFailed() 

  • onAuthenticationError:指纹识别异常回调,包含几个常用错误码,详见:
  • onAuthenticationSucceeded:指纹识别通过回调
  • onAuthenticationFailed:指纹识别不通过回调

onAuthenticationError 错误码

/**
 * An error code that may be returned during authentication.
 */
@IntDef(
    ERROR_HW_UNAVAILABLE,
    ERROR_UNABLE_TO_PROCESS,
    ERROR_TIMEOUT,
    ERROR_NO_SPACE,
    ERROR_CANCELED,
    ERROR_LOCKOUT,
    ERROR_VENDOR,
    ERROR_LOCKOUT_PERMANENT,
    ERROR_USER_CANCELED,
    ERROR_NO_BIOMETRICS,
    ERROR_HW_NOT_PRESENT,
    ERROR_NEGATIVE_BUTTON,
    ERROR_NO_DEVICE_CREDENTIAL
)
@Retention(RetentionPolicy.SOURCE)
@interface AuthenticationError 

上面伪代码中authenticate方法的参数,为设置验证指纹弹窗的基础参数,代码大概长这样:

val promptInfo: BiometricPrompt.PromptInfo = BiometricPrompt.PromptInfo.Builder()
    .setTitle("这里设置Title")
    .setSubtitle("这里设置Subtitle")
    .setDescription("这里设置Description")
    // .setDeviceCredentialAllowed(false)
    .setNegativeButtonText("这里设置关闭按钮文案")
    // .setAllowedAuthenticators()
    .setConfirmationRequired(true)
    .build()

流程很简单,下面提供一个工具类,可以直接拿去用:

BiometricUtils.kt

package com.kongqw.fingerprintdemo

import android.content.Context
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity

class BiometricUtils 

    private val mBuilder: BiometricPrompt.PromptInfo.Builder = BiometricPrompt.PromptInfo.Builder()

    private var mBiometricPrompt: BiometricPrompt? = null

    private var mAuthenticationErrorListener: IAuthenticationErrorListener? = null

    private var mAuthenticationSucceededListener: IAuthenticationSucceededListener? = null

    private var mAuthenticationFailedListener: IAuthenticationFailedListener? = null

    /**
     * 是否支持指纹识别
     */
    fun isSupportBiometric(context: Context): Boolean 
        return try 
            BiometricManager.BIOMETRIC_SUCCESS == BiometricManager.from(context).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
         catch (e: Exception) 
            e.printStackTrace()
            false
        
    

    fun setTitle(title: String): BiometricUtils 
        mBuilder.setTitle(title)
        return this
    

    fun setSubtitle(subtitle: String): BiometricUtils 
        mBuilder.setSubtitle(subtitle)
        return this
    

    fun setDescription(description: String): BiometricUtils 
        mBuilder.setDescription(description)
        return this
    

    fun setNegativeButtonText(negativeButtonText: String): BiometricUtils 
        mBuilder.setNegativeButtonText(negativeButtonText)
        return this
    

    fun setAuthenticationErrorListener(listener: IAuthenticationErrorListener): BiometricUtils 
        mAuthenticationErrorListener = listener
        return this
    

    fun setAuthenticationSucceededListener(listener: IAuthenticationSucceededListener): BiometricUtils 
        mAuthenticationSucceededListener = listener
        return this
    

    fun setAuthenticationFailedListener(listener: IAuthenticationFailedListener): BiometricUtils 
        mAuthenticationFailedListener = listener
        return this
    

    fun authenticate(fragmentActivity: FragmentActivity, succeededListener: IAuthenticationSucceededListener? = null, errorListener: IAuthenticationErrorListener? = null) 
        succeededListener?.apply  mAuthenticationSucceededListener = succeededListener 
        errorListener?.apply  mAuthenticationErrorListener = errorListener 
        mBiometricPrompt = BiometricPrompt(fragmentActivity, /* command -> command?.run() ,*/ FingerCallBack())
        mBiometricPrompt?.authenticate(mBuilder.build())
    

    fun authenticate(fragment: Fragment, succeededListener: IAuthenticationSucceededListener? = null, errorListener: IAuthenticationErrorListener? = null) 
        succeededListener?.apply  mAuthenticationSucceededListener = succeededListener 
        errorListener?.apply  mAuthenticationErrorListener = errorListener 
        mBiometricPrompt = BiometricPrompt(fragment, /* command -> command?.run() ,*/ FingerCallBack())
        mBiometricPrompt?.authenticate(mBuilder.build())
    

    inner class FingerCallBack : BiometricPrompt.AuthenticationCallback() 

        override fun onAuthenticationError(errorCode: Int, errString: CharSequence) 
            super.onAuthenticationError(errorCode, errString)
            mAuthenticationErrorListener?.onAuthenticationError(errorCode, errString)
        

        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) 
            super.onAuthenticationSucceeded(result)
            mBiometricPrompt?.cancelAuthentication()
            mAuthenticationSucceededListener?.onAuthenticationSucceeded(result)
        

        override fun onAuthenticationFailed() 
            super.onAuthenticationFailed()
            mAuthenticationFailedListener?.onAuthenticationFailed()
        
    
    
    interface IAuthenticationErrorListener 
        fun onAuthenticationError(errorCode: Int, errString: CharSequence)
    

    interface IAuthenticationSucceededListener 
        fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult)
    

    interface IAuthenticationFailedListener 
        fun onAuthenticationFailed()
    

使用

初始化

private val mBiometricUtils = BiometricUtils()

检查是否支持指纹验证

val isSupportBiometric = mBiometricUtils.isSupportBiometric(applicationContext)

开始验证

mBiometricUtils.setTitle("指纹验证")
    .setSubtitle("需要身份验证")
    .setDescription("Description")
    .setNegativeButtonText("关闭吧")
    .setAuthenticationSucceededListener(object : BiometricUtils.IAuthenticationSucceededListener 
        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) 
            Toast.makeText(applicationContext, "指纹通过", Toast.LENGTH_SHORT).show()
        
    )
    .setAuthenticationFailedListener(object : BiometricUtils.IAuthenticationFailedListener 
        override fun onAuthenticationFailed() 
            Toast.makeText(applicationContext, "指纹不通过", Toast.LENGTH_SHORT).show()
        
    )
    .setAuthenticationErrorListener(object : BiometricUtils.IAuthenticationErrorListener 
        override fun onAuthenticationError(errorCode: Int, errString: CharSequence) 
            // when(errorCode)
            //     BiometricPrompt.ERROR_HW_UNAVAILABLE -> ""
            //     BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> ""
            //     BiometricPrompt.ERROR_TIMEOUT -> ""
            //     BiometricPrompt.ERROR_NO_SPACE -> ""
            //     BiometricPrompt.ERROR_CANCELED -> ""
            //     BiometricPrompt.ERROR_LOCKOUT -> ""
            //     BiometricPrompt.ERROR_VENDOR -> ""
            //     BiometricPrompt.ERROR_LOCKOUT_PERMANENT -> ""
            //     BiometricPrompt.ERROR_USER_CANCELED -> ""
            //     BiometricPrompt.ERROR_NO_BIOMETRICS -> "未注册任何指纹"
            //     BiometricPrompt.ERROR_HW_NOT_PRESENT -> ""
            //     BiometricPrompt.ERROR_NEGATIVE_BUTTON -> ""
            //     BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> ""
            // 
            Toast.makeText(applicationContext, "onAuthenticationError($errorCode, $errString)", Toast.LENGTH_SHORT).show()
        
    )

mBiometricUtils.authenticate(this)

以上是关于Android 指纹验证的主要内容,如果未能解决你的问题,请参考以下文章

Android 指纹验证

Android 指纹验证

彻底搞懂 CookieSessionTokenJWT

傻傻分不清之 CookieSessionTokenJWT

一篇文章教你从入门到精通 Google 指纹验证功能

如何从 Android KeyGuardmanager 中删除指纹认证?