Android 指紋識別(給應用添加指紋解鎖)

使用指紋

說明 : 指紋解鎖在23 的時候,官方就已經給出了api ,但是由於Android市場複雜,無法形成統一,硬件由不同的廠商開發,導致相同版本的軟件系統,搭載的硬件千變萬化,導致由的機型不支持指紋識別,但是,這也擋不住指紋識別在接下來的時間中進入Android市場的趨勢,因爲它相比較輸入密碼或圖案,它更加簡單,相比較密碼或者圖案,它更炫酷 ,本文Demo 使用最新的28 支持的androidx 庫中的API及最近火熱的kotlin語言完成的


 需要知道的

  1. FingerprintManager : 指紋管理工具類
  2. FingerprintManager.AuthenticationCallback :使用驗證的時候傳入該接口,通過該接口進行驗證結果回調
  3. FingerprintManager.CryptoObject: FingerprintManager 支持的分裝加密對象的類

 以上是28以下API 中使用的類 在Android 28版本中google 宣佈使用Androidx 庫代替Android庫,所以在28版本中Android 推薦使用androidx庫中的類 所以在本文中我 使用的是推薦是用的FingerprintManagerCompat 二者的使用的方式基本相似


如何使用指紋

  • 開始驗證 ,系統默認的每段時間驗證指紋次數爲5次 次數用完之後自動關閉驗證,並且30秒之內不允行在使用驗證

驗證的方法是authenticate()

/**
*
*@param crypto object associated with the call or null if none required.
* @param flags optional flags; should be 0
* @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param handler an optional handler for events
**/
@RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
    public void authenticate(@Nullable CryptoObject crypto, int flags,
            @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback,
            @Nullable Handler handler) {
        if (Build.VERSION.SDK_INT >= 23) {
            final FingerprintManager fp = getFingerprintManagerOrNull(mContext);
            if (fp != null) {
                android.os.CancellationSignal cancellationSignal = cancel != null
                        ? (android.os.CancellationSignal) cancel.getCancellationSignalObject()
                        : null;
                fp.authenticate(
                        wrapCryptoObject(crypto),
                        cancellationSignal,
                        flags,
                        wrapCallback(callback),
                        handler);
            }
        }
    }

arg1: 用於通過指紋驗證取出AndroidKeyStore中key的值 
arg2: 系統建議爲0
arg3: 取消指紋驗證 手動關閉驗證 可以調用該參數的cancel方法
arg4:返回驗證結果
arg5: Handler fingerprint 中的 
消息都是通過handler來傳遞的 如果不需要則傳null 會自動默認創建一個主線程的handler來傳遞消息


使用指紋識別的條件

 

通過零碎的知識完成一個Demo 

 

 

  • 添加權限(這個權限不需要在6.0中做處理)
  • 判斷硬件是否支持
  • 是否已經設置了鎖屏 並且已經有一個被錄入的指紋
  • 判斷是否至少存在一條指紋信息

指紋識別通過之後跳轉到 指定頁面

進入之後首先彈出對話框,進行指紋驗證

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/fingerprint" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="驗證指紋" />

    <TextView
        android:id="@+id/fingerprint_error_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:maxLines="1" />

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="5dp"
        android:background="#696969" />

    <TextView
        android:id="@+id/fingerprint_cancel_tv"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="取消"
        android:textSize="16sp" />

</LinearLayout>

使用DialogFragment 完成對話框 新建一個DialogFragment 並且初始化相關的api

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //獲取fingerprintManagerCompat對象
        fingerprintManagerCompat = FingerprintManagerCompat.from(context!!)
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog)
    }

在界面顯示在前臺的時候開始掃描

override fun onResume() {
        super.onResume()
        startListening()
    }
@SuppressLint("MissingPermission")
    private fun startListening() {
        isSelfCancelled = false
        mCancellationSignal = CancellationSignal()
        fingerprintManagerCompat.authenticate(FingerprintManagerCompat.CryptoObject(mCipher), 0, mCancellationSignal, object : FingerprintManagerCompat.AuthenticationCallback() {
        //驗證錯誤
            override fun onAuthenticationError(errMsgId: Int, errString: CharSequence?) {
                if (!isSelfCancelled) {
                    errorMsg.text = errString
                    if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                        Toast.makeText(mActivity, errString, Toast.LENGTH_SHORT).show()
                        dismiss()
                        mActivity.finish()
                    }
                }
            }
                //成功
            override fun onAuthenticationSucceeded(result: FingerprintManagerCompat.AuthenticationResult?) {
                MainActivity.startActivity(mActivity, true)
            }
            //錯誤時提示幫助,比如說指紋錯誤,我們將顯示在界面上 讓用戶知道情況
            override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence?) {
                errorMsg.text = helpString
            }
            //驗證失敗
            override fun onAuthenticationFailed() {
                errorMsg.text = "指紋驗證失敗,請重試"
            }
        }, null)
    }

在不可見的時候停止驗證

if (null != mCancellationSignal) {
            mCancellationSignal.cancel()
            isSelfCancelled = true
        }

在MainActivity 中首先判斷是否驗證成功 是 跳轉到目標頁 否則的話需要進行驗證 
在這個過程中我們需要做的就是判斷是否支持,判斷是否滿足指紋驗證的條件(條件在上面)

if (intent.getBooleanExtra("isSuccess", false)) {
            WelcomeActivity.startActivity(this)
            finish()
        } else {
            //判斷是否支持該功能
            if (supportFingerprint()) {
                initKey() //生成一個對稱加密的key
                initCipher() //生成一個Cipher對象
            }
        }

驗證條件

 if (Build.VERSION.SDK_INT < 23) {
            Toast.makeText(this, "系統不支持指紋功能", Toast.LENGTH_SHORT).show()
            return false
        } else {
            val keyguardManager = getSystemService(KeyguardManager::class.java)
            val managerCompat = FingerprintManagerCompat.from(this)
            if (!managerCompat.isHardwareDetected) {
                Toast.makeText(this, "系統不支持指紋功能", Toast.LENGTH_SHORT).show()
                return false
            } else if (!keyguardManager.isKeyguardSecure) {
                Toast.makeText(this, "屏幕未設置鎖屏 請先設置鎖屏並添加一個指紋", Toast.LENGTH_SHORT).show()
                return false
            } else if (!managerCompat.hasEnrolledFingerprints()) {
                Toast.makeText(this, "至少在系統中添加一個指紋", Toast.LENGTH_SHORT).show()
                return false
            }
        }

必須生成一個加密的key 和一個Cipher對象

//生成Cipher
private fun initCipher() {
        val key = keyStore.getKey(DEFAULT_KEY_NAME, null) as SecretKey
        val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                + KeyProperties.BLOCK_MODE_CBC + "/"
                + KeyProperties.ENCRYPTION_PADDING_PKCS7)
        cipher.init(Cipher.ENCRYPT_MODE, key)
        showFingerPrintDialog(cipher)
    }
    //生成一個key
private fun initKey() {
        keyStore = KeyStore.getInstance("AndroidKeyStore")
        keyStore.load(null)
        val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
        val builder = KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setUserAuthenticationRequired(true)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
        keyGenerator.init(builder.build())
        keyGenerator.generateKey()
    }

 驗證成功就可

 

 

 

 

 

 

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