אחת מהשיטות להגנה על מידע רגיש או תוכן פרימיום באפליקציה היא לבקש אימות ביומטרי, כמו שימוש בזיהוי פנים או בזיהוי טביעת אצבע. במדריך הזה מוסבר איך לתמוך בתהליכי כניסה ביומטריים באפליקציה.
ככלל, מומלץ להשתמש ב-Credential Manager לכניסה הראשונית למכשיר. אפשר לבצע הרשאות חוזרות באמצעות ההנחיה לביומטריה או באמצעות מנהל פרטי הכניסה. היתרון של השימוש בהודעה ביומטרית הוא שהוא מציע עוד אפשרויות להתאמה אישית, ואילו 'מנהל פרטי הכניסה' מאפשר הטמעה אחת בשני התהליכים.
הצהרה על סוגי האימות שהאפליקציה תומכת בהם
כדי להגדיר את סוגי האימות שהאפליקציה תומכת בהם, משתמשים בממשק BiometricManager.Authenticators
. המערכת מאפשרת להצהיר על סוגי האימות הבאים:
BIOMETRIC_STRONG
- אימות באמצעות זיהוי ביומטרי מסוג 3, כפי שמוגדר בדף הגדרת התאימות ל-Android.
BIOMETRIC_WEAK
- אימות באמצעות זיהוי ביומטרי מסוג 2, כפי שמוגדר בדף הגדרת התאימות ל-Android.
DEVICE_CREDENTIAL
- אימות באמצעות פרטי כניסה לנעילת מסך – קוד האימות, קו ביטול הנעילה או הסיסמה של המשתמש.
כדי להתחיל להשתמש במאמת, המשתמש צריך ליצור קוד אימות, קו ביטול נעילה או סיסמה. אם למשתמש עדיין אין חשבון, תופיע בקשה ליצור חשבון בתהליך ההרשמה הביומטרי.
כדי להגדיר את סוגי האימות הביומטרי שהאפליקציה תקבל, מעבירים את סוג האימות או שילוב של סוגי אימות בביטים לשיטה setAllowedAuthenticators()
. קטע הקוד הבא מסביר איך לתמוך באימות באמצעות פרטי כניסה ביומטריים מסוג Class 3 או פרטי כניסה לנעילת מסך.
Kotlin
// Lets the user authenticate using either a Class 3 biometric or // their lock screen credential (PIN, pattern, or password). promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setAllowedAuthenticators(BIOMETRIC_STRONG or DEVICE_CREDENTIAL) .build()
Java
// Lets user authenticate using either a Class 3 biometric or // their lock screen credential (PIN, pattern, or password). promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) .build();
השילובים הבאים של סוגי מאמתים לא נתמכים ב-Android 10 (API ברמה 29) וגרסאות קודמות: DEVICE_CREDENTIAL
ו-BIOMETRIC_STRONG | DEVICE_CREDENTIAL
. כדי לבדוק אם יש קוד אימות, קו ביטול נעילה או סיסמה ב-Android מגרסה 10 ומטה, משתמשים בשיטה KeyguardManager.isDeviceSecure()
.
בודקים אם האימות הביומטרי זמין
אחרי שמחליטים באילו רכיבי אימות האפליקציה תומכת, צריך לבדוק אם הרכיבים האלה זמינים. כדי לעשות זאת, מעבירים את אותו שילוב של סוגי ביטים שהצהרתם עליו באמצעות השיטה setAllowedAuthenticators()
לשיטה canAuthenticate()
.
אם צריך, מפעילים את פעולת הכוונה ACTION_BIOMETRIC_ENROLL
. ב-intent extra, מציינים את קבוצת מאמתי החשבונות שהאפליקציה מקבלת. הכוונה הזו מבקשת מהמשתמש לרשום פרטי כניסה לאימות שהאפליקציה מקבלת.
Kotlin
val biometricManager = BiometricManager.from(this) when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) { BiometricManager.BIOMETRIC_SUCCESS -> Log.d("MY_APP_TAG", "App can authenticate using biometrics.") BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> Log.e("MY_APP_TAG", "No biometric features available on this device.") BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> Log.e("MY_APP_TAG", "Biometric features are currently unavailable.") BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> { // Prompts the user to create credentials that your app accepts. val enrollIntent = Intent(Settings.ACTION_BIOMETRIC_ENROLL).apply { putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG or DEVICE_CREDENTIAL) } startActivityForResult(enrollIntent, REQUEST_CODE) } }
Java
BiometricManager biometricManager = BiometricManager.from(this); switch (biometricManager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) { case BiometricManager.BIOMETRIC_SUCCESS: Log.d("MY_APP_TAG", "App can authenticate using biometrics."); break; case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE: Log.e("MY_APP_TAG", "No biometric features available on this device."); break; case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE: Log.e("MY_APP_TAG", "Biometric features are currently unavailable."); break; case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED: // Prompts the user to create credentials that your app accepts. final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL); enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG | DEVICE_CREDENTIAL); startActivityForResult(enrollIntent, REQUEST_CODE); break; }
איך לקבוע איך המשתמש ביצע אימות
אחרי שהמשתמש יאומת, תוכלו לבדוק אם הוא אומת באמצעות פרטי כניסה של המכשיר או באמצעות פרטי כניסה ביומטריים, על ידי קריאה ל-getAuthenticationType()
.
הצגת ההנחיה להתחברות
כדי להציג הודעת מערכת שמבקשת מהמשתמש לבצע אימות באמצעות פרטי כניסה ביומטריים, משתמשים בספרייה הביומטרית. תיבת הדו-שיח הזו שסופקת על ידי המערכת עקבית בכל האפליקציות שמשתמשות בה, וכך יוצרת חוויית משתמש אמינה יותר. תיבת דו-שיח לדוגמה מופיעה באיור 1.
כדי להוסיף לאפליקציה אימות ביומטרי באמצעות ספריית Biometric:
בקובץ
build.gradle
של מודול האפליקציה, מוסיפים תלות בספרייהandroidx.biometric
.בפעילות או בקטע שמארחים את תיבת הדו-שיח להתחברות ביומטרית, מציגים את תיבת הדו-שיח באמצעות הלוגיקה שמוצגת בקטע הקוד הבא:
Kotlin
private lateinit var executor: Executor private lateinit var biometricPrompt: BiometricPrompt private lateinit var promptInfo: BiometricPrompt.PromptInfo override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) executor = ContextCompat.getMainExecutor(this) biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { super.onAuthenticationError(errorCode, errString) Toast.makeText(applicationContext, "Authentication error: $errString", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationSucceeded( result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) Toast.makeText(applicationContext, "Authentication succeeded!", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationFailed() { super.onAuthenticationFailed() Toast.makeText(applicationContext, "Authentication failed", Toast.LENGTH_SHORT) .show() } }) promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setNegativeButtonText("Use account password") .build() // Prompt appears when user clicks "Log in". // Consider integrating with the keystore to unlock cryptographic operations, // if needed by your app. val biometricLoginButton = findViewById<Button>(R.id.biometric_login) biometricLoginButton.setOnClickListener { biometricPrompt.authenticate(promptInfo) } }
Java
private Executor executor; private BiometricPrompt biometricPrompt; private BiometricPrompt.PromptInfo promptInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); executor = ContextCompat.getMainExecutor(this); biometricPrompt = new BiometricPrompt(MainActivity.this, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { super.onAuthenticationError(errorCode, errString); Toast.makeText(getApplicationContext(), "Authentication error: " + errString, Toast.LENGTH_SHORT) .show(); } @Override public void onAuthenticationSucceeded( @NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); Toast.makeText(getApplicationContext(), "Authentication succeeded!", Toast.LENGTH_SHORT).show(); } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_SHORT) .show(); } }); promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setNegativeButtonText("Use account password") .build(); // Prompt appears when user clicks "Log in". // Consider integrating with the keystore to unlock cryptographic operations, // if needed by your app. Button biometricLoginButton = findViewById(R.id.biometric_login); biometricLoginButton.setOnClickListener(view -> { biometricPrompt.authenticate(promptInfo); }); }
שימוש בפתרון קריפטוגרפיה שמבוסס על אימות
כדי להגן טוב יותר על מידע רגיש באפליקציה, אפשר לשלב קריפטוגרפיה בתהליך העבודה של האימות הביומטרי באמצעות מכונה של CryptoObject
.
המסגרת תומכת באובייקטים הקריפטוגרפיים הבאים: Signature
, Cipher
ו-Mac
.
אחרי שהמשתמש מבצע אימות באמצעות הנחיה ביומטרית, האפליקציה יכולה לבצע פעולה קריפטוגרפית. לדוגמה, אם מבצעים אימות באמצעות אובייקט Cipher
, האפליקציה תוכל לבצע הצפנה ופענוח באמצעות אובייקט SecretKey
.
בקטעים הבאים מפורטות דוגמאות לשימוש באובייקט Cipher
ובאובייקט SecretKey
כדי להצפין נתונים. בכל דוגמה נעשה שימוש ב-methods:
Kotlin
private fun generateSecretKey(keyGenParameterSpec: KeyGenParameterSpec) { val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } private fun getSecretKey(): SecretKey { val keyStore = KeyStore.getInstance("AndroidKeyStore") // Before the keystore can be accessed, it must be loaded. keyStore.load(null) return keyStore.getKey(KEY_NAME, null) as SecretKey } private fun getCipher(): Cipher { return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7) }
Java
private void generateSecretKey(KeyGenParameterSpec keyGenParameterSpec) { KeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); keyGenerator.init(keyGenParameterSpec); keyGenerator.generateKey(); } private SecretKey getSecretKey() { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); // Before the keystore can be accessed, it must be loaded. keyStore.load(null); return ((SecretKey)keyStore.getKey(KEY_NAME, null)); } private Cipher getCipher() { return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); }
אימות באמצעות פרטי כניסה ביומטריים בלבד
אם האפליקציה משתמשת במפתח סודי שמחייב ביטול נעילה של פרטי כניסה ביומטריים, המשתמש יצטרך לאמת את פרטי הכניסה הביומטריים שלו בכל פעם לפני שהאפליקציה תיגש למפתח.
כדי להצפין מידע רגיש רק אחרי שהמשתמש מבצע אימות באמצעות פרטי כניסה ביומטריים, מבצעים את הפעולות הבאות:
יוצרים מפתח עם ההגדרות הבאות של
KeyGenParameterSpec
:Kotlin
generateSecretKey(KeyGenParameterSpec.Builder( KEY_NAME, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) // Invalidate the keys if the user has registered a new biometric // credential, such as a new fingerprint. Can call this method only // on Android 7.0 (API level 24) or higher. The variable // "invalidatedByBiometricEnrollment" is true by default. .setInvalidatedByBiometricEnrollment(true) .build())
Java
generateSecretKey(new KeyGenParameterSpec.Builder( KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) // Invalidate the keys if the user has registered a new biometric // credential, such as a new fingerprint. Can call this method only // on Android 7.0 (API level 24) or higher. The variable // "invalidatedByBiometricEnrollment" is true by default. .setInvalidatedByBiometricEnrollment(true) .build());
הפעלת תהליך עבודה של אימות ביומטרי שכולל צופן:
Kotlin
biometricLoginButton.setOnClickListener { // Exceptions are unhandled within this snippet. val cipher = getCipher() val secretKey = getSecretKey() cipher.init(Cipher.ENCRYPT_MODE, secretKey) biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher)) }
Java
biometricLoginButton.setOnClickListener(view -> { // Exceptions are unhandled within this snippet. Cipher cipher = getCipher(); SecretKey secretKey = getSecretKey(); cipher.init(Cipher.ENCRYPT_MODE, secretKey); biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher)); });
בקריאות החזרה (callbacks) של האימות הביומטרי, משתמשים במפתח הסודי כדי להצפין את המידע הרגיש:
Kotlin
override fun onAuthenticationSucceeded( result: BiometricPrompt.AuthenticationResult) { val encryptedInfo: ByteArray = result.cryptoObject.cipher?.doFinal( // plaintext-string text is whatever data the developer would like // to encrypt. It happens to be plain-text in this example, but it // can be anything plaintext-string.toByteArray(Charset.defaultCharset()) ) Log.d("MY_APP_TAG", "Encrypted information: " + Arrays.toString(encryptedInfo)) }
Java
@Override public void onAuthenticationSucceeded( @NonNull BiometricPrompt.AuthenticationResult result) { // NullPointerException is unhandled; use Objects.requireNonNull(). byte[] encryptedInfo = result.getCryptoObject().getCipher().doFinal( // plaintext-string text is whatever data the developer would like // to encrypt. It happens to be plain-text in this example, but it // can be anything plaintext-string.getBytes(Charset.defaultCharset())); Log.d("MY_APP_TAG", "Encrypted information: " + Arrays.toString(encryptedInfo)); }
אימות באמצעות פרטי כניסה ביומטריים או פרטי כניסה של נעילת מסך
אפשר להשתמש במפתח סודי שמאפשר אימות באמצעות פרטי כניסה ביומטריים או פרטי כניסה למסך הנעילה (קוד אימות, קו ביטול נעילה או סיסמה). כשמגדירים את המפתח הזה, צריך לציין תקופת תוקף. במהלך פרק הזמן הזה, האפליקציה יכולה לבצע כמה פעולות קריפטוגרפיות בלי שהמשתמש יצטרך לבצע אימות מחדש.
כדי להצפין מידע רגיש אחרי שהמשתמש מבצע אימות באמצעות פרטי כניסה ביומטריים או באמצעות מסך הנעילה, מבצעים את הפעולות הבאות:
יוצרים מפתח באמצעות ההגדרה הבאה של
KeyGenParameterSpec
:Kotlin
generateSecretKey(KeyGenParameterSpec.Builder( KEY_NAME, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) .setUserAuthenticationParameters(VALIDITY_DURATION_SECONDS, ALLOWED_AUTHENTICATORS) .build())
Java
generateSecretKey(new KeyGenParameterSpec.Builder( KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) .setUserAuthenticationParameters(VALIDITY_DURATION_SECONDS, ALLOWED_AUTHENTICATORS) .build());
תוך פרק זמן של
VALIDITY_DURATION_SECONDS
אחרי שהמשתמש יבצע אימות, צריך להצפין את המידע הרגיש:Kotlin
private fun encryptSecretInformation() { // Exceptions are unhandled for getCipher() and getSecretKey(). val cipher = getCipher() val secretKey = getSecretKey() try { cipher.init(Cipher.ENCRYPT_MODE, secretKey) val encryptedInfo: ByteArray = cipher.doFinal( // plaintext-string text is whatever data the developer would // like to encrypt. It happens to be plain-text in this example, // but it can be anything plaintext-string.toByteArray(Charset.defaultCharset())) Log.d("MY_APP_TAG", "Encrypted information: " + Arrays.toString(encryptedInfo)) } catch (e: InvalidKeyException) { Log.e("MY_APP_TAG", "Key is invalid.") } catch (e: UserNotAuthenticatedException) { Log.d("MY_APP_TAG", "The key's validity timed out.") biometricPrompt.authenticate(promptInfo) }
Java
private void encryptSecretInformation() { // Exceptions are unhandled for getCipher() and getSecretKey(). Cipher cipher = getCipher(); SecretKey secretKey = getSecretKey(); try { // NullPointerException is unhandled; use Objects.requireNonNull(). ciper.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedInfo = cipher.doFinal( // plaintext-string text is whatever data the developer would // like to encrypt. It happens to be plain-text in this example, // but it can be anything plaintext-string.getBytes(Charset.defaultCharset())); } catch (InvalidKeyException e) { Log.e("MY_APP_TAG", "Key is invalid."); } catch (UserNotAuthenticatedException e) { Log.d("MY_APP_TAG", "The key's validity timed out."); biometricPrompt.authenticate(promptInfo); } }
אימות באמצעות מפתחות לאימות לפי שימוש
אפשר לספק תמיכה במפתחות לאימות לשימוש חד-פעמי במכונה של BiometricPrompt
. כדי להשתמש במפתח כזה, המשתמש צריך להציג פרטי כניסה ביומטריים או פרטי כניסה למכשיר בכל פעם שהאפליקציה צריכה לגשת לנתונים שמאובטחים על ידי המפתח. מפתחות לאימות בכל שימוש יכולים להיות שימושיים בעסקאות בעלות גבוהה, כמו ביצוע תשלום גדול או עדכון של רשומות רפואיות של אדם.
כדי לשייך אובייקט BiometricPrompt
למפתח לאימות לפי שימוש, מוסיפים קוד דומה לקוד הבא:
Kotlin
val authPerOpKeyGenParameterSpec = KeyGenParameterSpec.Builder("myKeystoreAlias", key-purpose) // Accept either a biometric credential or a device credential. // To accept only one type of credential, include only that type as the // second argument. .setUserAuthenticationParameters(0 /* duration */, KeyProperties.AUTH_BIOMETRIC_STRONG or KeyProperties.AUTH_DEVICE_CREDENTIAL) .build()
Java
KeyGenParameterSpec authPerOpKeyGenParameterSpec = new KeyGenParameterSpec.Builder("myKeystoreAlias", key-purpose) // Accept either a biometric credential or a device credential. // To accept only one type of credential, include only that type as the // second argument. .setUserAuthenticationParameters(0 /* duration */, KeyProperties.AUTH_BIOMETRIC_STRONG | KeyProperties.AUTH_DEVICE_CREDENTIAL) .build();
אימות ללא פעולה מפורשת של המשתמש
כברירת מחדל, המערכת דורשת מהמשתמשים לבצע פעולה ספציפית, כמו לחיצה על לחצן, אחרי שהם מקבלים את פרטי הכניסה הביומטריים. כדאי להשתמש בהגדרה הזו אם באפליקציה מוצגת תיבת דו-שיח לאישור פעולה רגישת או מסוכנת, כמו ביצוע רכישה.
עם זאת, אם באפליקציה מוצג תיבת דו-שיח של אימות ביומטרי לפעולה עם סיכון נמוך יותר, תוכלו לספק למערכת רמז לכך שהמשתמש לא צריך לאשר את האימות. ההצעה הזו יכולה לאפשר למשתמש לצפות בתוכן באפליקציה מהר יותר אחרי ביצוע אימות חוזר באמצעות מודל פסיבי, כמו זיהוי פנים או זיהוי קשתית העין. כדי לספק את ההצעה הזו, מעבירים את הערך false
לשיטה setConfirmationRequired()
.
באיור 2 מוצגות שתי גרסאות של אותה תיבת דו-שיח. בגרסה אחת נדרשת פעולה מפורשת של המשתמש, ובגרסה השנייה לא.
קטע הקוד הבא מראה איך להציג תיבת דו-שיח שלא מחייבת פעולה מפורשת מצד המשתמש כדי להשלים את תהליך האימות:
Kotlin
// Lets the user authenticate without performing an action, such as pressing a // button, after their biometric credential is accepted. promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setNegativeButtonText("Use account password") .setConfirmationRequired(false) .build()
Java
// Lets the user authenticate without performing an action, such as pressing a // button, after their biometric credential is accepted. promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setNegativeButtonText("Use account password") .setConfirmationRequired(false) .build();
מתן אפשרות לשימוש בפרטי כניסה לא ביומטריים כחלופה
אם אתם רוצים שהאפליקציה תאפשר אימות באמצעות פרטי כניסה ביומטריים או פרטי כניסה של המכשיר, תוכלו להצהיר שהאפליקציה תומכת בפרטי כניסה של המכשיר על ידי הוספת הערך DEVICE_CREDENTIAL
לקבוצת הערכים שאתם מעבירים אל setAllowedAuthenticators()
.
אם האפליקציה שלכם משתמשת כרגע ב-createConfirmDeviceCredentialIntent()
או ב-setDeviceCredentialAllowed()
כדי לספק את היכולת הזו, עליכם לעבור לשימוש ב-setAllowedAuthenticators()
.
מקורות מידע נוספים
למידע נוסף על אימות ביומטרי ב-Android, אפשר לעיין במקורות המידע הבאים.