Android指紋識別,看這一篇就夠了


在Android6.0(Api23)的時候,Android系統加入了指紋識別的api接口,即FingerprintManager,定義了最基礎的指紋識別接口。不過,在AndroidP(Api28)的時候,官方不再推薦使用,做了@Deprecated處理。

后來,在support v4庫中添加了FingerprintManagerCompat類,我看了他的源碼,其實就是對FingerprintManager做了一定的封裝,比如做了對SDK版本的判斷、對于加密部分的處理等等,其本質還是在用FingerprintManager來實現指紋識別功能。

到了AndroidP,FingerprintManager就正式退役了,系統新增了BiometricPrompt接口,從接口名字'生物識別'也能看出來,今后的安全驗證功能,將不會局限于指紋了,應該還會加入面部識別等等。

下面就通過我寫的一個demo,展開來介紹一下FingerprintManager以及BiometricPrompt

一、公共部分:

1、總的來說,我們寫一個Manager類,類的內部通過Api版本的判斷,來分別實現Api23和Api28的適配


分別根據Api版本來實例化兩個類

2、其中,判斷版本號的辦法是:


判斷版本號

3、其次,我們聲明了一個接口IBiometricPromptImpl,Api28和Api23的實例都要繼承他


接口

3、對于系統是否支持指紋識別的判斷:


四個判斷一起來做出最后的判斷

demo中的表現

分別說明一下判斷的細節:

isAboveApi23():上面已經說過了;
isHardwareDetected(): 這是用來判斷系統硬件是否支持指紋識別,這里也是分情況判斷,但是AndroidP還不知道用什么確切的辦法來判斷,所以暫時用與AndroidM一樣的方式。Api23的具體實現在實現類中,后續你會看到

isHardwareDetected()

hasEnrolledFingerprints():這個方法是用來判斷你的設備在系統設置里面是否設置了指紋。
如果用戶沒有設置,這時候你可以引導他去設置。不過,我查了一下,各個廠家的設置指紋的頁面Activity名都不是統一的,所以這里要一一做適配能累成狗。所以如果要引導的話,引導到安全設置頁面就可以了,安全設置頁面系統有統一的Intent,是【Settings.ACTION_SECURITY_SETTINGS】。

hasEnrolledFingerprints()

isKeyguardSecure():這個方法是判斷系統有沒有設置鎖屏。
這個方法我認為是個雞肋,因為現在如果你設置了指紋的話,肯定要讓你先設置一種密碼(PIN/Password/Pattern),那么鎖屏肯定也就隨之設置了,不理解為啥還要判斷一下這個。。。

isKeyguardSecure()

二、BiometricPromptApi23: 針對Api23~Api27的部分

1、authenticate()

在看BiometricPromptApi23.java里面的內容之前,我們先需要了解一下指紋識別的關鍵方法:authenticate()

authenticate方法

上圖是google的api文檔中的描述,現在我們挨個解釋一下這些參數都是什么:
①. crypto這是一個加密類的對象,指紋掃描器會使用這個對象來判斷認證結果的合法性。這個對象可以是null,但是這樣的話,就意味這app無條件信任認證的結果,雖然從理論上這個過程可能被攻擊,數據可以被篡改,這是app在這種情況下必須承擔的風險。因此,建議這個參數不要置為null。這個類的實例化有點麻煩,主要使用javax的security接口實現,后面我的demo程序中會給出一個helper類(CryptoObjectHelper.java),這個類封裝內部實現的邏輯,開發者可以直接使用我的類簡化實例化的過程。
②. cancel這個是CancellationSignal類的一個對象,這個對象用來在指紋識別器掃描用戶指紋的是時候取消當前的掃描操作,如果不取消的話,那么指紋掃描器會移植掃描直到超時(一般為30s,取決于具體的廠商實現),這樣的話就會比較耗電。建議這個參數不要置為null。
③. flags 標識位,根據上圖的文檔描述,這個位暫時應該為0,這個標志位應該是保留將來使用的。
④.callback這個是FingerprintManager.AuthenticationCallback類的對象,這個是這個接口中除了第一個參數之外最重要的參數了,稍后我們詳細來介紹。這個參數不能為NULL。
⑤. handler 這是Handler類的對象,如果這個參數不為null的話,那么FingerprintManager將會使用這個handler中的looper來處理來自指紋識別硬件的消息。通常來講,開發這不用提供這個參數,可以直接置為null,因為FingerprintManager會默認使用app的main looper來處理。

2、指紋認證之后的回調方法

這里就要介紹的是上面提到的FingerprintManager.AuthenticationCallback了,因為掃描指紋和認證的過程都是在另外一個進程中完成的,所以我們需要采取異步的方式,等操作完成之后,讓系統回調給我們,回調方法就是AuthenticationCallback類中的4個方法了

四個回調方法

下面我們簡要介紹一下這些接口的含義:
①. OnAuthenticationError(int errorCode, ICharSequence errString) 這個接口會再系統指紋認證出現不可恢復的錯誤的時候才會調用,并且參數errorCode就給出了錯誤碼,標識了錯誤的原因。
在AndroidP以前,這個方法回調回來之后,指紋識別sensor將會被關閉,也就是說,你再把手指放在指紋硬件上,將不會有反應了。這時候你需要提示用戶關閉指紋識別彈窗,或改用密碼支付等等
什么情況下會回調error錯誤呢?比如,連續識別錯誤5次指紋、指紋硬件不可用等等。
②. OnAuthenticationFailed()這個接口會在系統指紋認證失敗的情況的下才會回調。注意這里的認證失敗和上面的認證錯誤是不一樣的,雖然結果都是不能認證。認證失敗是指所有的信息都采集完整,并且沒有任何異常,但是這個指紋和之前注冊的指紋是不相符的;但是認證錯誤是指在采集或者認證的過程中出現了錯誤,比如指紋傳感器工作異常等。也就是說認證失敗是一個可以預期的正常情況,而認證錯誤是不可預期的異常情況。
③.OnAuthenticationHelp(int helpMsgId, ICharSequence helpString)上面的認證失敗是認證過程中的一個異常情況,我們說那種情況是因為出現了不可恢復的錯誤,而我們這里的OnAuthenticationHelp方法是出現了可以回復的異常才會調用的。什么是可以恢復的異常呢?一個常見的例子就是:手指移動太快,當我們把手指放到傳感器上的時候,如果我們很快地將手指移走的話,那么指紋傳感器可能只采集了部分的信息,因此認證會失敗。但是這個錯誤是可以恢復的,因此只要提示用戶再次按下指紋,并且不要太快移走就可以解決。
④. OnAuthenticationSucceeded(FingerprintManagerCompati.AuthenticationResult result)這個接口會在認證成功之后回調。我們可以在這個方法中提示用戶認證成功。這里需要說明一下,如果我們上面在調用authenticate的時候,我們的CryptoObject不是null的話,那么我們在這個方法中可以通過AuthenticationResult來獲得Cypher對象然后調用它的doFinal方法。doFinal方法會檢查結果是不是會攔截或者篡改過,如果是的話會拋出一個異常。當我們發現這些異常的時候都應該將認證當做是失敗來來處理,為了安全建議大家都這么做。

好了,下面來看看我的demo里的實現



這個authenticate方法是重寫了IBiometricPromptImpl接口中的方法,重要的部分我已經加了注釋,剩下的應該能看懂了吧,不懂的可以在評論中問~~【手動笑臉?】


實現了指紋識別的回調類

打開dialog,等待識別

識別出錯了

識別成功,之后自動關閉dialog

下面是兩個判斷方法的實現


判斷是否硬件支持和是否設置了指紋

三、BiometricPromptApi28: 針對Api28及以后的平臺

在AndroidP中,原來的fingerprintManager將被BiometricPrompt類替換,Google旨在統一生物識別的方式(雖然目前api中還沒有看到虹膜、面部識別等),包括UI,UI也不允許自定義了,必須使用BiometricPrompt.Builder來創建對話框,其中可以自定義title、subtitle、description和一個NegativeButton(也就是cancel鍵)。

AndroidP中系統對話框的表現

創建對話框

只有一個NegativeButton,這個很尷尬,意思是只能有button存在界面上,如果我想加個UsePassword的button,只能把這個cancel鍵給改掉。。。(不過,大家放心,雖然AndroidP的source還沒有放出來,不過,我讓老同事幫忙找了一分BiometricPrompt的源碼,里面還是有一個PositiveButton的,只不過api應該還沒有放出來)

下面來看看實現代碼:
構造方法,創建signature對象(對于加密這塊理解的不好,哪位大神可以給普及普及)


構造方法

跟Api23很像,實現authenticate方法


authenticate方法

回調
回調方法

附上源碼:有問題可以探討:https://github.com/gaoyangcr7/BiometricPromptDemo

常見問題:

1,報錯 java.io.IOException: Failed to find byte code for android/hardware/biometrics/BiometricPrompt$AuthenticationCallback

去設置里把InstantRun關掉就好了

2,報錯 java.lang.RuntimeException: java.security.InvalidAlgorithmParameterException: java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
  1. 這個異常不是模擬器上才出現的,真機也會,和設備無關,懷疑是谷歌 API 的坑
  2. 我的做法是catch住異常,友好提示用戶暫不支持指紋,引導用戶使用其他的驗證方式
  3. 備用做法是:直接使用無密鑰驗證,但是有一定的安全風險,目前在觀察線上用戶出現頻率,再考慮是否用備用方案。
1,小米6、6X手機上點擊“Turn On Identification”的時候會先走一遍onAuthenticationHelp,helpCode=1021,helpString為空

應該是MIUI自行修改了底層時間,可以嘗試晚一點調用authenticate方法(沒試驗過,主要手邊沒小米手機)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 好久沒寫文章了,最近也比較偷懶,今天繼續討論我實際開發中遇到的需求,那就是關于APP解鎖,大家都知道。現在越來越多...
    青蛙要fly閱讀 3,118評論 2 26
  • 一、 指紋識別接口從Android 6.0開始,Android系統加上了對指紋識別的支持。所有指紋識別的接口都在...
    Qi0907閱讀 1,471評論 0 1
  • 指紋識別-Android @(Android進階資料)[Android, 學習, 讀書筆記, Markdown]指...
    辰曦小雨閱讀 1,617評論 3 6
  • 最近項目中添加了一個新的登錄方式:指紋識別。好巧不巧這塊分給了我,然后一頓研究。下面想把一些實現的代碼貼出來做個筆...
    SHERLOCKvv閱讀 24,029評論 6 28
  • 中午的時候媽媽發了一條朋友圈,是剛做好的燜面,想起來上次吃燜面還是寒假過年回家的時候,心中略數了一下大概還要三個...
    余余不吃魚閱讀 666評論 0 2