在Android6.0(Api23)的時候丈牢,Android系統(tǒng)加入了指紋識別的api接口,即
FingerprintManager
瞄沙,定義了最基礎(chǔ)的指紋識別接口己沛。不過,在AndroidP(Api28)的時候距境,官方不再推薦使用申尼,做了@Deprecated處理。
后來肮疗,在support v4庫中添加了FingerprintManagerCompat
類,我看了他的源碼扒接,其實就是對FingerprintManager
做了一定的封裝伪货,比如做了對SDK版本的判斷、對于加密部分的處理等等钾怔,其本質(zhì)還是在用FingerprintManager
來實現(xiàn)指紋識別功能碱呼。
到了AndroidP,FingerprintManager
就正式退役了宗侦,系統(tǒng)新增了BiometricPrompt
接口愚臀,從接口名字'生物識別'也能看出來,今后的安全驗證功能矾利,將不會局限于指紋了姑裂,應(yīng)該還會加入面部識別等等。
下面就通過我寫的一個demo男旗,展開來介紹一下FingerprintManager
以及BiometricPrompt
舶斧。
一、公共部分:
1察皇、總的來說茴厉,我們寫一個Manager類,類的內(nèi)部通過Api版本的判斷什荣,來分別實現(xiàn)Api23和Api28的適配
2矾缓、其中,判斷版本號的辦法是:
3稻爬、其次嗜闻,我們聲明了一個接口IBiometricPromptImpl,Api28和Api23的實例都要繼承他
3桅锄、對于系統(tǒng)是否支持指紋識別的判斷:
分別說明一下判斷的細(xì)節(jié):
①isAboveApi23()
:上面已經(jīng)說過了泞辐;
②isHardwareDetected()
: 這是用來判斷系統(tǒng)硬件是否支持指紋識別笔横,這里也是分情況判斷,但是AndroidP還不知道用什么確切的辦法來判斷咐吼,所以暫時用與AndroidM一樣的方式吹缔。Api23的具體實現(xiàn)在實現(xiàn)類中,后續(xù)你會看到
③hasEnrolledFingerprints()
:這個方法是用來判斷你的設(shè)備在系統(tǒng)設(shè)置里面是否設(shè)置了指紋锯茄。
如果用戶沒有設(shè)置厢塘,這時候你可以引導(dǎo)他去設(shè)置。不過肌幽,我查了一下晚碾,各個廠家的設(shè)置指紋的頁面Activity名都不是統(tǒng)一的,所以這里要一一做適配能累成狗喂急。所以如果要引導(dǎo)的話格嘁,引導(dǎo)到安全設(shè)置頁面就可以了,安全設(shè)置頁面系統(tǒng)有統(tǒng)一的Intent廊移,是【Settings.ACTION_SECURITY_SETTINGS
】糕簿。
④isKeyguardSecure()
:這個方法是判斷系統(tǒng)有沒有設(shè)置鎖屏。
這個方法我認(rèn)為是個雞肋狡孔,因為現(xiàn)在如果你設(shè)置了指紋的話懂诗,肯定要讓你先設(shè)置一種密碼(PIN/Password/Pattern),那么鎖屏肯定也就隨之設(shè)置了苗膝,不理解為啥還要判斷一下這個殃恒。。辱揭。
二离唐、BiometricPromptApi23: 針對Api23~Api27的部分
1、authenticate()
在看BiometricPromptApi23.java
里面的內(nèi)容之前问窃,我們先需要了解一下指紋識別的關(guān)鍵方法:authenticate()
侯繁。
上圖是google的api文檔中的描述,現(xiàn)在我們挨個解釋一下這些參數(shù)都是什么:
①.
crypto
這是一個加密類的對象泡躯,指紋掃描器會使用這個對象來判斷認(rèn)證結(jié)果的合法性贮竟。這個對象可以是null,但是這樣的話较剃,就意味這app無條件信任認(rèn)證的結(jié)果咕别,雖然從理論上這個過程可能被攻擊,數(shù)據(jù)可以被篡改写穴,這是app在這種情況下必須承擔(dān)的風(fēng)險惰拱。因此,建議這個參數(shù)不要置為null啊送。這個類的實例化有點麻煩偿短,主要使用javax的security接口實現(xiàn)欣孤,后面我的demo程序中會給出一個helper類(CryptoObjectHelper.java
),這個類封裝內(nèi)部實現(xiàn)的邏輯昔逗,開發(fā)者可以直接使用我的類簡化實例化的過程降传。②.
cancel
這個是CancellationSignal
類的一個對象,這個對象用來在指紋識別器掃描用戶指紋的是時候取消當(dāng)前的掃描操作勾怒,如果不取消的話婆排,那么指紋掃描器會移植掃描直到超時(一般為30s,取決于具體的廠商實現(xiàn))笔链,這樣的話就會比較耗電段只。建議這個參數(shù)不要置為null。③.
flags
標(biāo)識位鉴扫,根據(jù)上圖的文檔描述赞枕,這個位暫時應(yīng)該為0,這個標(biāo)志位應(yīng)該是保留將來使用的坪创。④.
callback
這個是FingerprintManager.AuthenticationCallback
類的對象炕婶,這個是這個接口中除了第一個參數(shù)之外最重要的參數(shù)了,稍后我們詳細(xì)來介紹误堡。這個參數(shù)不能為NULL古话。⑤.
handler
這是Handler類的對象雏吭,如果這個參數(shù)不為null的話锁施,那么FingerprintManager
將會使用這個handler中的looper來處理來自指紋識別硬件的消息。通常來講杖们,開發(fā)這不用提供這個參數(shù)悉抵,可以直接置為null,因為FingerprintManager
會默認(rèn)使用app的main looper來處理摘完。
2姥饰、指紋認(rèn)證之后的回調(diào)方法
這里就要介紹的是上面提到的FingerprintManager.AuthenticationCallback
了,因為掃描指紋和認(rèn)證的過程都是在另外一個進(jìn)程中完成的孝治,所以我們需要采取異步的方式列粪,等操作完成之后,讓系統(tǒng)回調(diào)給我們谈飒,回調(diào)方法就是AuthenticationCallback
類中的4個方法了
下面我們簡要介紹一下這些接口的含義:
①.
OnAuthenticationError(int errorCode, ICharSequence errString)
這個接口會再系統(tǒng)指紋認(rèn)證出現(xiàn)不可恢復(fù)的錯誤的時候才會調(diào)用岂座,并且參數(shù)errorCode就給出了錯誤碼,標(biāo)識了錯誤的原因杭措。在AndroidP以前费什,這個方法回調(diào)回來之后,指紋識別sensor將會被關(guān)閉手素,也就是說鸳址,你再把手指放在指紋硬件上瘩蚪,將不會有反應(yīng)了。這時候你需要提示用戶關(guān)閉指紋識別彈窗稿黍,或改用密碼支付等等
什么情況下會回調(diào)error錯誤呢疹瘦?比如,連續(xù)識別錯誤5次指紋闻察、指紋硬件不可用等等拱礁。
②.
OnAuthenticationFailed()
這個接口會在系統(tǒng)指紋認(rèn)證失敗的情況的下才會回調(diào)。注意這里的認(rèn)證失敗和上面的認(rèn)證錯誤是不一樣的辕漂,雖然結(jié)果都是不能認(rèn)證呢灶。認(rèn)證失敗是指所有的信息都采集完整,并且沒有任何異常钉嘹,但是這個指紋和之前注冊的指紋是不相符的鸯乃;但是認(rèn)證錯誤是指在采集或者認(rèn)證的過程中出現(xiàn)了錯誤,比如指紋傳感器工作異常等跋涣。也就是說認(rèn)證失敗是一個可以預(yù)期的正常情況缨睡,而認(rèn)證錯誤是不可預(yù)期的異常情況。③.
OnAuthenticationHelp(int helpMsgId, ICharSequence helpString)
上面的認(rèn)證失敗是認(rèn)證過程中的一個異常情況陈辱,我們說那種情況是因為出現(xiàn)了不可恢復(fù)的錯誤奖年,而我們這里的OnAuthenticationHelp方法是出現(xiàn)了可以回復(fù)的異常才會調(diào)用的。什么是可以恢復(fù)的異常呢沛贪?一個常見的例子就是:手指移動太快陋守,當(dāng)我們把手指放到傳感器上的時候,如果我們很快地將手指移走的話利赋,那么指紋傳感器可能只采集了部分的信息水评,因此認(rèn)證會失敗。但是這個錯誤是可以恢復(fù)的媚送,因此只要提示用戶再次按下指紋中燥,并且不要太快移走就可以解決。④.
OnAuthenticationSucceeded(FingerprintManagerCompati.AuthenticationResult result)
這個接口會在認(rèn)證成功之后回調(diào)塘偎。我們可以在這個方法中提示用戶認(rèn)證成功疗涉。這里需要說明一下,如果我們上面在調(diào)用authenticate的時候吟秩,我們的CryptoObject不是null的話咱扣,那么我們在這個方法中可以通過AuthenticationResult來獲得Cypher對象然后調(diào)用它的doFinal方法。doFinal方法會檢查結(jié)果是不是會攔截或者篡改過峰尝,如果是的話會拋出一個異常偏窝。當(dāng)我們發(fā)現(xiàn)這些異常的時候都應(yīng)該將認(rèn)證當(dāng)做是失敗來來處理,為了安全建議大家都這么做。好了祭往,下面來看看我的demo里的實現(xiàn)
這個authenticate方法是重寫了IBiometricPromptImpl接口中的方法伦意,重要的部分我已經(jīng)加了注釋,剩下的應(yīng)該能看懂了吧硼补,不懂的可以在評論中問~~【手動笑臉?】
下面是兩個判斷方法的實現(xiàn)
三已骇、BiometricPromptApi28: 針對Api28及以后的平臺
在AndroidP中离钝,原來的fingerprintManager
將被BiometricPrompt
類替換,Google旨在統(tǒng)一生物識別的方式(雖然目前api中還沒有看到虹膜褪储、面部識別等)卵渴,包括UI,UI也不允許自定義了鲤竹,必須使用BiometricPrompt.Builder
來創(chuàng)建對話框浪读,其中可以自定義title、subtitle辛藻、description和一個NegativeButton(也就是cancel鍵)碘橘。
只有一個NegativeButton,這個很尷尬吱肌,意思是只能有button存在界面上痘拆,如果我想加個UsePassword的button,只能把這個cancel鍵給改掉氮墨。纺蛆。。(不過勇边,大家放心犹撒,雖然AndroidP的source還沒有放出來折联,不過粒褒,我讓老同事幫忙找了一分BiometricPrompt的源碼,里面還是有一個PositiveButton的诚镰,只不過api應(yīng)該還沒有放出來)
下面來看看實現(xiàn)代碼:
構(gòu)造方法奕坟,創(chuàng)建signature對象(對于加密這塊理解的不好,哪位大神可以給普及普及)
跟Api23很像清笨,實現(xiàn)authenticate方法
回調(diào)
附上源碼:有問題可以探討:https://github.com/gaoyangcr7/BiometricPromptDemo
常見問題:
1月杉,報錯 java.io.IOException: Failed to find byte code for android/hardware/biometrics/BiometricPrompt$AuthenticationCallback
去設(shè)置里把InstantRun關(guān)掉就好了
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)
- 這個異常不是模擬器上才出現(xiàn)的抠艾,真機(jī)也會苛萎,和設(shè)備無關(guān),懷疑是谷歌 API 的坑
- 我的做法是catch住異常,友好提示用戶暫不支持指紋腌歉,引導(dǎo)用戶使用其他的驗證方式
- 備用做法是:直接使用無密鑰驗證蛙酪,但是有一定的安全風(fēng)險,目前在觀察線上用戶出現(xiàn)頻率翘盖,再考慮是否用備用方案桂塞。
1,小米6馍驯、6X手機(jī)上點擊“Turn On Identification”的時候會先走一遍onAuthenticationHelp阁危,helpCode=1021,helpString為空
應(yīng)該是MIUI自行修改了底層時間汰瘫,可以嘗試晚一點調(diào)用authenticate方法(沒試驗過狂打,主要手邊沒小米手機(jī))