On me demande de montrer certains éléments de l'interface utilisateur en fonction de la présence de matériel biométrique. Pour Android 23-27 j'utilise FingerprintManager#isHardwareDetected()
et FingerprintManager#hasEnrolledFingerprints()
. Les deux sont déconseillés dans Android 28.
Je comprends que je peux obtenir ces informations en utilisant BiometricPrompt#authenticate(...)
et en recevant BiometricPrompt#BIOMETRIC_ERROR_HW_NOT_PRESENT
Ou BiometricPrompt#BIOMETRIC_ERROR_NO_BIOMETRICS
Dans la méthode BiometricPrompt.AuthenticationCallback#onAuthenticationError(int errorCode, ...)
. Mais cela entraînerait l'affichage de BiometricPrompt
sur les périphériques de support, ce qui n'est pas souhaitable. L'utilisation de CancellationSignal
ne semble pas non plus être une solution, car je ne saurais pas quand annuler l'invite.
Existe-t-il un moyen de détecter la présence de matériel biométrique et l'inscription d'utilisateurs?
Google a finalement résolu ce problème avec Android Q
La méthode Android.hardware.biometrics.BiometricManager # canAuthenticate () peut être utilisée pour déterminer si la biométrie peut être utilisée.
La méthode peut être utilisée pour déterminer si du matériel biométrique est présent et si l'utilisateur est inscrit ou non.
Renvoie BIOMETRIC_ERROR_NONE_ENROLLED si l'utilisateur n'en a aucun inscrit, ou BIOMETRIC_ERROR_HW_UNAVAILABLE si aucun n'est actuellement pris en charge/activé. Renvoie BIOMETRIC_SUCCESS si un biométrique peut actuellement être utilisé (inscrit et disponible).
Espérons que cela soit ajouté au androidx.biometric:biometric
bibliothèque, donc il peut être utilisé sur tous les appareils.
Jusque-là, la solution de @algrid fonctionne pour déterminer l'inscription biométrique.
Et ce qui suit peut être utilisé pour déterminer si un lecteur d'empreintes digitales est présent.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
Malheureusement, Google ne résoudrait pas ce problème après avoir changé le statut du problème associé en "Ne résoudra pas (comportement prévu)". Je préfère utiliser l'ancienne API obsolète pour l'instant.
Mais pour ceux qui veulent utiliser la nouvelle API, il existe un moyen hacky/laid d'obtenir un analogue de hasEnrolledFingerprints()
(le code est pour API23 +):
public boolean isBiometryAvailable() {
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (Exception e) {
return false;
}
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (NoSuchAlgorithmException |
NoSuchProviderException e) {
return false;
}
if (keyGenerator == null || keyStore == null) {
return false;
}
try {
keyStore.load(null);
keyGenerator.init(new
KeyGenParameterSpec.Builder("dummy_key",
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
| CertificateException | IOException e) {
return false;
}
return true;
}
Ceci est basé sur l'instruction Android keystore docs suivante:
- L'authentification utilisateur autorise une opération cryptographique spécifique associée à une clé. Dans ce mode, chaque opération impliquant une telle clé doit être autorisée individuellement par l'utilisateur. Actuellement, le seul moyen d'une telle autorisation est l'authentification par empreinte digitale: FingerprintManager.authenticate. De telles clés ne peuvent être générées ou importées que si au moins une empreinte digitale est inscrite (voir FingerprintManager.hasEnrolledFingerprints). Ces clés deviennent définitivement invalides une fois qu'une nouvelle empreinte digitale est enregistrée ou que toutes les empreintes digitales sont désinscrites.
Voir la section "Exiger une authentification utilisateur pour l'utilisation des clés" ici https://developer.Android.com/training/articles/keystore
J'ai écrit cette méthode pour Kotlin:
fun checkForBiometrics() : Boolean{
Log.d(TAG, "checkForBiometrics started")
var canAuthenticate = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT < 29) {
val keyguardManager : KeyguardManager = applicationContext.getSystemService(KEYGUARD_SERVICE) as KeyguardManager
val packageManager : PackageManager = applicationContext.packageManager
if(!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
Log.w(TAG, "checkForBiometrics, Fingerprint Sensor not supported")
canAuthenticate = false
}
if (!keyguardManager.isKeyguardSecure) {
Log.w(TAG, "checkForBiometrics, Lock screen security not enabled in Settings")
canAuthenticate = false
}
} else {
val biometricManager : BiometricManager = this.getSystemService(BiometricManager::class.Java)
if(biometricManager.canAuthenticate() != BiometricManager.BIOMETRIC_SUCCESS){
Log.w(TAG, "checkForBiometrics, biometrics not supported")
canAuthenticate = false
}
}
}else{
canAuthenticate = false
}
Log.d(TAG, "checkForBiometrics ended, canAuthenticate=$canAuthenticate ")
return canAuthenticate
}
De plus, vous devez implémenter sur votre fichier gradle d'application comme dépendance:
implementation 'androidx.biometric:biometric:1.0.0-alpha04'
et utilisez également les outils de construction les plus récents:
compileSdkVersion 29
buildToolsVersion "29.0.1"
La bibliothèque biométrique AndroidX a commencé à fournir ce type d'informations à partir de la version 1.0.0-beta01
(androidx.biometric:biometric:1.0.0-beta01
)
BiometricManager.from(context).canAuthenticate()
Qui renvoie l'un des
Voir le journal des modifications: https://developer.Android.com/jetpack/androidx/releases/biometric#1.0.0-beta01 =
La méthode - vérifie que l'utilisateur a l'autorisation d'authentification biométrique activée pour l'application avant d'utiliser le gestionnaire de packages pour vérifier que l'authentification par empreinte digitale est disponible sur l'appareil. Et même il vérifiera si l'utilisateur est inscrit ou non.
implémentation 'androidx.biometric: biométrique: 1.0.0-alpha03'
private Boolean checkBiometricSupport() {
KeyguardManager keyguardManager =
(KeyguardManager) getSystemService(KEYGUARD_SERVICE);
PackageManager packageManager = this.getPackageManager();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
notifyUser("This Android version does not support fingerprint authentication.");
return false;
}
if(!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
{
notifyUser("Fingerprint Sensor not supported");
return false;
}
if (!keyguardManager.isKeyguardSecure()) {
notifyUser("Lock screen security not enabled in Settings");
return false;
}
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.USE_BIOMETRIC) !=
PackageManager.PERMISSION_GRANTED) {
notifyUser("Fingerprint authentication permission not enabled");
return false;
}
return true;
}
Pour ceux qui ne veulent pas attendre la sortie de la bibliothèque de support, vous pouvez utiliser la construction nocturne comme ceci
repositories {
maven {
url "https://ci.Android.com/builds/submitted/5795878/androidx_snapshot/latest/repository/"
}
}
implementation group: 'androidx.biometric', name: 'biometric', version: '1.0.0-SNAPSHOT'
obtenir la version de construction d'ici
https://ci.Android.com/builds/branches/aosp-androidx-master-dev/
branche aosp-androidx-master-dev
afficher la dernière version de androidx-snapshot
Il existe une méthode de classe FingerprintManagerCompat.from(this).isHardwareDetected
androidx.core.hardware.fingerprint
paquet.