今天的文章要來實作關於生物辨識...或稱指紋辨識的功能
說到生物辨識,記得最早接觸到這個概念的還隸屬蘋果吧,我第一次拿到Iphone 6s(二手)時感受到了指紋辨識的美好(笑
後來過了好幾年拿到Iphone 10(二手)的時候又感受到了人臉辨識的美好
明明是Android工程師卻都拿蘋果手機
咳咳,總之就在我時常在想為何Android一直都不出指紋辨識的相關機種時,沒想到早在Android很前面的時代就有了(跪
然後更妙的是,我居然一直都沒有去寫這個功能...|・ω・)
好啦,總之本文就來寫一下關於生物辨識
不過有鑒於目前Android的人臉辨識機種還不多,而且模擬器好像也沒辦法測
因此這部分功能暫時跳過,等以後有機會會在寫一篇
好的,那這篇就是要來寫指紋辨識,直接看功能吧!
還有Github
->https://github.com/thumbb13555/AndroidBlogExamples/tree/main/BiometricExample
好,開始!
1. 設定模擬器&載入套件
好的,既然要開發指紋辨識,那當然得先找有支援指紋辨識的機種.....屁啦,並不需要
其實Android studio 的模擬器本身就有該模擬該功能的設置囉!
那首先,我們要先在模擬器裡登錄指紋
聲明一下,我用的模擬器是Google Pixel 2, API 30的機種
其實什麼機種都行,不過基本上有支援指紋辨識的機種還是Google的親孩子比較多啦XDD
開好模擬器後,基本上該機種的指紋登錄在Setting->Securly裏面
然後拉到底下,Fingerprint的部分
而關於按指紋的部分,請點模擬器的圖中位置
然後找到Fingerprint的部分
就可以登錄指紋囉!
而Android的生物辨識部分,雖然原生的Android就有BiometricManager的套件,不過官方文檔也是提供androidx的套件使用
那麼,就請打開build.gradle
並把套件載入dependencies吧!
dependencies { implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' implementation "androidx.biometric:biometric:1.1.0" }
最後記得要Sync呦!(・ω・)b
2. 撰寫介面&功能
好的,接著進入主要功能的區域
首先介面就兩個按鈕,速速帶過!
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btPIN" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="PIN碼登錄" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline2" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.5" /> <Button android:id="@+id/btFinger" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:text="指紋登錄" app:layout_constraintBottom_toTopOf="@+id/guideline2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
再來是主要程式的其中一部分
我想大部人也都知道,因為Android廠家眾多,所以也未必每個機種都有生物辨識....甚至可能連PIN碼驗證都沒有(跪
因此,在寫功能之前我們必須先判斷該手機有沒有生物辨識的功能
其程式如下
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btPIN, btFinger; btFinger = findViewById(R.id.btFinger); btPIN = findViewById(R.id.btPIN); BiometricManager manager = BiometricManager.from(this); switch (manager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) { case BiometricManager.BIOMETRIC_SUCCESS: Toast.makeText(this, "本裝置可以使用Pin Code或者指紋登錄", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE: Toast.makeText(this, "本裝置不支援指紋登錄", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE: Toast.makeText(this, "生物認證功能目前不可用", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED: //表示該裝置使用者沒有登錄指紋(但裝置支援) final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL); enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG | DEVICE_CREDENTIAL); startActivity(enrollIntent); break; } btFinger.setOnClickListener(v -> { }); btPIN.setOnClickListener(v -> { }); }
這邊需要注意一件事,就是這裡的BiometricManager套件在import時需要選擇androidx.biometric哦!
主要內容上面的註解都寫了,就自己看吧!
需要注意的也只有要記得import對的套件~
3. 撰寫主要驗證程式
好的,接下來就是重點了
一般來說,我們在做驗證的時候通常會想要優先使用指紋,假設使用者沒登錄或者不方便使用指紋的情況才改去使用Pin碼做驗證
也或許,使用者就乾脆不想用指紋,就是想輸入PIN碼也說不定
因此我寫的內容就針對這兩部分有做出區別,請看Code
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btPIN, btFinger; btFinger = findViewById(R.id.btFinger); btPIN = findViewById(R.id.btPIN); BiometricManager manager = BiometricManager.from(this); switch (manager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) { case BiometricManager.BIOMETRIC_SUCCESS: Toast.makeText(this, "本裝置可以使用Pin Code或者指紋登錄", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE: Toast.makeText(this, "本裝置不支援指紋登錄", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE: Toast.makeText(this, "生物認證功能目前不可用", Toast.LENGTH_SHORT).show(); break; case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED: //表示該裝置使用者沒有登錄指紋(但裝置支援) final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL); enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG | DEVICE_CREDENTIAL); startActivity(enrollIntent); break; } btFinger.setOnClickListener(v -> { //如果登錄指紋就會直接跳成PIN碼登錄 startBiometricPrompt(getInfo(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)); }); btPIN.setOnClickListener(v -> { startBiometricPrompt(getInfo(DEVICE_CREDENTIAL)); }); } private BiometricPrompt.PromptInfo getInfo(int method) { return new BiometricPrompt.PromptInfo.Builder() .setTitle("登錄") .setSubtitle("Balabala") .setAllowedAuthenticators(method) .build(); } private void startBiometricPrompt(BiometricPrompt.PromptInfo promptInfo) { Executor executor = ContextCompat.getMainExecutor(this); BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor , new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { super.onAuthenticationError(errorCode, errString); } @Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); Toast.makeText(MainActivity.this, "登錄成功", Toast.LENGTH_SHORT).show(); } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); } }); biometricPrompt.authenticate(promptInfo); } }
首先幾個步驟,首先要先設定關於彈出的視窗內容
這個內容的話,我們將在BiometricPrompt.PromptInfo這個函式中設定
而我把它包裝在了粉底白字的getInfo的副程式中
再來是紫底白字的主要驗證功能的部分,最大的一大坨就是Callback,也就是完成驗證後的回傳
最後,橘底白字的部分當然就是最最最重要的,也就是將先前的資訊載入
基本上就這三個大點是特別要注意的
此外,綠底白字的部分是控制控制要使用的驗證方法
一般來說,如果想要使用者用指紋或者PIN碼驗證的話,在該方法輸入
BIOMETRIC_STRONG | DEVICE_CREDENTIAL
就可以實現(也就是會優先用生物辨識,如果輸入錯誤或者突然不想用的時候就可以切換)
或者只輸入
DEVICE_CREDENTIAL
的話,就不使用指紋辨識,直接使用PIN碼驗證囉!
4. 關於onAuthenticationSucceeded
中的BiometricPrompt.AuthenticationResult
有些細心的人可能會注意到,在Successed中有個回調
@Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); }
這部分我承認,我到現在還搞不清楚他到底是打算拿來幹嘛用的
雖然我參考了官方文檔
-> https://developer.android.com/training/sign-in/biometric-auth
不過我還是一直想像不出使用這個功能的場景
而關於這部分的功能,其實我原本是打算做的,也因此研究了整個下午
不過最後實在得不出它的存在意義,也坦白說不知道該如何介紹
所以我想,這部分我就只放上我參考過的連結Github,然後請各位自己研究研究吧
-> https://github.com/isaidamier/blogs.biometrics.cryptoBlog
其實我感覺今天的功能不算太難,我幾乎還測試跟取財只花了一個小時左右就弄好了
不過在最後一段有說,光研究那個CryptoObject的應用場景跟內容就搞了一整個下午
然後研究無果,還是放棄了.....
最後這篇文在深夜才發出QAQ
好啦,總之我日後如果有想到這部分的功能的話,我在另外寫一篇發表囉
那希望大家都能夠成功實現功能!
留言列表