Android指紋校驗與生物識別的使用

Android在6.0的時候提供了官方的指紋模塊API,最近在使用的時候發現以前的FingerprintManager已經被標識爲過時了。
在這裏插入圖片描述
Android 8.0 整合了一套生物識別模塊,指紋識別使用BiometricPrompt來調用。
官方文檔:FingerprintManager

官方文檔:BiometricPrompt

寫代碼用過時API當然沒排面啦,於是我轉用了BiometricPrompt,但是也有一個問題,這個API是Android 28才能使用的,也就是說6.0,7.0的手機無法使用,7.0目前還是有一些使用率的,爲了能夠讓所有支持指紋的Android手機都可以使用我兩種方法都寫了,使用策略模式封裝了一下,直接看代碼吧,使用Kotlin編寫。

使用策略模式

關於策略模式的使用可以看我之前的這篇博客
策略模式

定義接口FingerPrintStrategy

interface FingerPrintStrategy {
    fun authenticate()//驗證指紋
    fun cancelAuthenticate()//取消驗證
}

定義回調接口

interface FingerprintResultCallback {
    fun onSucceeded(result:String)
    fun onFailed()
    fun onError(errorCode:Int,errorMessage:String)
}

FingerprintManager策略具體實現

@TargetApi(23)
class FingerprintStrategyForM(context: Context, callback: FingerprintResultCallback) : FingerPrintStrategy{
    private val TAG = "FingerprintStrategyForM"
    private val mContext = context
    private var mCancellationSignal: CancellationSignal? = null
    private var mFingerprintManager: FingerprintManager? = null
    private var mCipher: Cipher? = null
    private var mCallback:FingerprintResultCallback = callback
    init {
        mFingerprintManager = mContext.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager
        mCancellationSignal = CancellationSignal()
        mCancellationSignal!!.setOnCancelListener {
            PsyLog.d(TAG,"Canceled!!!")
        }
    }

	/**
	* 判斷手機是否有指紋模塊
	*/
    private fun hasFingerHardware():Boolean{
        if (mFingerprintManager == null){
            return false
        }
        return mFingerprintManager!!.isHardwareDetected
    }
	/**
	* 判斷用戶是否給手機錄入過指紋
	*/
    private fun hasFingerInput():Boolean{
        if (mFingerprintManager == null){
            return false
        }
        return mFingerprintManager!!.hasEnrolledFingerprints()
    }
	/**
	* 指紋校驗具體實現
	*/
    override fun authenticate() {
        if (!hasFingerHardware()){
            mCallback.onError(BIOMETRIC_ERROR_HW_NOT_PRESENT,mContext.getString(R.string.phone_no_biometric_sensor))
            return
        }
        if (!hasFingerInput()){
            mCallback.onError(BIOMETRIC_ERROR_NO_BIOMETRICS,mContext.getString(R.string.phone_not_input_fingerprint))
            return
        }
        mFingerprintManager?.authenticate(null,mCancellationSignal,0,object:FingerprintManager.AuthenticationCallback(){
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
                super.onAuthenticationError(errorCode, errString)
                mCallback.onError(errorCode,errString.toString())
            }

            override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult?) {
                super.onAuthenticationSucceeded(result)
                mCallback.onSucceeded(result.toString())
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                mCallback.onFailed()
            }
        },null)
    }
	/**
	* 取消校驗
	*/
    override fun cancelAuthenticate() {
        mCancellationSignal?.cancel()
    }

}

BiometricPrompt策略具體實現

@TargetApi(28)
class FingerprintStrategyForP(context:Context, callback:FingerprintResultCallback):FingerPrintStrategy {
    private val TAG = "FingerprintStrategyForP"
    private val mContext:Context = context
    private var mCancellationSignal: CancellationSignal? = null
    private var mBiometricPrompt: BiometricPrompt? = null
    private var mAuthenticationCallback: BiometricPrompt.AuthenticationCallback? = null
    private val mCallback = callback
    init {
    	//setNegativeButton在這裏是必須的,不寫會報錯,校驗指紋是的UI必須有取消響應,此時按back鍵沒用的
        mBiometricPrompt = BiometricPrompt.Builder(mContext)
            .setTitle(mContext.getString(R.string.authentication))
            .setDescription(mContext.getString(R.string.please_press_the_fingerprint_sensing_area_to_verify_the_fingerprint))
            .setNegativeButton(mContext.getString(R.string.cancel), getMainExecutor(mContext),
                DialogInterface.OnClickListener { dialog, which ->
                    PsyLog.d(TAG, "Cancel button clicked")
                    cancelAuthenticate()
                })
            .build()
        mCancellationSignal = CancellationSignal()
        mCancellationSignal!!.setOnCancelListener {
            PsyLog.d(TAG,"Canceled!!!")
        }

        mAuthenticationCallback = object : BiometricPrompt.AuthenticationCallback(){
        	//api版本判斷,是否有指紋傳感器等BiometricPrompt會自己判斷,在這裏返回
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
                super.onAuthenticationError(errorCode, errString)
                mCallback.onError(errorCode,errString.toString())
            }
			//校驗成功
            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                mCallback.onFailed()
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) {
                super.onAuthenticationSucceeded(result)
                mCallback.onSucceeded(result.toString())
            }
        }

    }
	/**
	* 指紋校驗具體實現
	*/
    override fun authenticate(){
        mBiometricPrompt!!.authenticate(mCancellationSignal!!, getMainExecutor(mContext), mAuthenticationCallback!!)
    }
	/**
	* 取消校驗具體實現
	*/
    override fun cancelAuthenticate(){
        mCancellationSignal?.cancel()
    }

}

定義異常碼

BiometricPrompt源碼中就有很多異常碼(官方文檔中異常碼定義
爲了返回值統一我們可以給FingerprintManager也定義一樣的異常碼。

const val BIOMETRIC_ERROR_HW_NOT_PRESENT = 12
const val BIOMETRIC_ERROR_HW_UNAVAILABLE = 1
const val BIOMETRIC_ERROR_LOCKOUT = 7
const val BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9
const val BIOMETRIC_ERROR_NO_BIOMETRICS = 11
const val BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14
const val BIOMETRIC_ERROR_NO_SPACE = 4
const val BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15
const val BIOMETRIC_ERROR_TIMEOUT = 3

具體操作類

我的建的工程minSDK設置就是23,所以這裏不用再判斷版本號是否小於Android M了。如果你的minSDK比23小,需要再這裏加一個判斷,小於23直接返回。

class FingerPrintHelper(context: Context,fingerprintResultCallback: FingerprintResultCallback ) {
	//api 28 以下使用FingerprintManager策略,以上用BiometricPrompt策略
    private var strategy:FingerPrintStrategy = if (Build.VERSION.SDK_INT<Build.VERSION_CODES.P){
        FingerprintStrategyForM(context,fingerprintResultCallback)
    }else{
        FingerprintStrategyForP(context,fingerprintResultCallback)
    }
    
    fun authenticate(){
        strategy.authenticate()
    }

    fun cancelAuthenticate(){
        strategy.cancelAuthenticate()
    }
}

使用時使用如下代碼就行了,

  FingerPrintHelper(mContext,
            object : FingerprintResultCallback {
                override fun onSucceeded(result: String) {
                    PsyLog.d(TAG, "onSucceeded")
                    //校驗成功,跳轉頁面
                }

                override fun onFailed() {
                    PsyLog.d(TAG, "onFailed")
                    //每次指紋識別沒通過都會走到這裏

                }

                override fun onError(errorCode: Int, errorMessage: String) {
                    PsyLog.d(TAG, "onError")
                    showMessage(errorMessage)
                    //這裏時一些錯誤情況,比如沒有指紋傳感器,錯誤太多指紋被鎖等
                }
            }).authenticate()

FingerPrintHelper引用了context,記得在生命週期結束的時候釋放掉,或者使用弱引用以防產生內存泄漏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章