Определите, присутствует ли биометрическое оборудование, и пользователь зарегистрировал биометрические данные на Android P

Мне предлагается показать определенные элементы пользовательского интерфейса в зависимости от наличия биометрического оборудования. Для Android 23-27 я использую FingerprintManager#isHardwareDetected() и FingerprintManager#hasEnrolledFingerprints(). Оба из них устарели в Android 28.

Я понимаю, что я могу получить эту информацию, используя BiometricPrompt#authenticate(...) и получение либо BiometricPrompt#BIOMETRIC_ERROR_HW_NOT_PRESENT или BiometricPrompt#BIOMETRIC_ERROR_NO_BIOMETRICS в BiometricPrompt.AuthenticationCallback#onAuthenticationError(int errorCode,...) метод. Но это приведет к тому, что BiometricPrompt будет показан на поддерживающих устройствах, что нежелательно. Использование CancellationSignal также не является решением, так как я не знаю, когда отменить приглашение.

Есть ли способ обнаружить присутствие биометрического оборудования и регистрацию пользователей?

Ответ 1

Google наконец-то решил эту проблему с Android Q

Метод android.hardware.biometrics.BiometricManager # canAuthenticate() можно использовать для определения возможности использования биометрии.

Этот метод можно использовать для определения наличия биометрического оборудования и регистрации пользователя.

Возвращает BIOMETRIC_ERROR_NONE_ENROLLED, если у пользователя нет зарегистрированных, или BIOMETRIC_ERROR_HW_UNAVAILABLE, если ни одна из них в настоящее время не поддерживается/не включена. Возвращает BIOMETRIC_SUCCESS, если в настоящее время можно использовать биометрические данные (зарегистрированы и доступны).

Надеемся, что это будет добавлено в библиотеку androidx.biometric:biometric, чтобы ее можно было использовать на всех устройствах.

До этого момента решение @algrid определяет количество участников биометрической регистрации.

Следующее может быть использовано для определения наличия сканера отпечатков пальцев.

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
            context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)

Ответ 2

К сожалению, Google не решит эту проблему, изменив статус связанной проблемы на "Не будет исправлено (намеренное поведение)". Сейчас я предпочитаю использовать старый устаревший API.

Но для тех, кто хочет использовать более новый API, есть хакерский/уродливый способ получить аналог hasEnrolledFingerprints() (код для 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;

}

Это основано на следующем утверждении документа хранилища ключей Android:

  • Аутентификация пользователя авторизует конкретную криптографическую операцию, связанную с одним ключом. В этом режиме каждая операция с таким ключом должна быть индивидуально авторизована пользователем. В настоящее время единственным средством такой авторизации является аутентификация по отпечатку пальца: FingerprintManager.authenticate. Такие ключи можно создавать или импортировать только в том случае, если зарегистрирован хотя бы один fingerprint (см. FingerprintManager.hasEnrolledFingerprints). Эти клавиши становятся недействительными после регистрации нового отпечатка пальца или отмены регистрации всех отпечатков пальцев.

См. раздел "Требуется аутентификация пользователя для использования ключа" здесь. https://developer.android.com/training/articles/keystore

Ответ 3

Биометрическая библиотека AndroidX начала предоставлять такую информацию из версии 1.0.0-beta01 (androidx.biometric:biometric:1.0.0-beta01)

BiometricManager.from(context).canAuthenticate()

Который возвращает один из

  • BIOMETRIC_SUCCESS
  • BIOMETRIC_ERROR_HW_UNAVAILABLE
  • BIOMETRIC_ERROR_NONE_ENROLLED
  • BIOMETRIC_ERROR_NO_HARDWARE

Смотрите список изменений: https://developer.android.com/jetpack/androidx/releases/biometric#1.0.0-beta01

Ответ 4

Я написал этот метод для 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
}

Дополнительно, вы должны внедрить в свой файл приложения gradle как зависимость:

implementation 'androidx.biometric:biometric:1.0.0-alpha04'

а также используйте новейшие инструменты сборки:

compileSdkVersion 29
buildToolsVersion "29.0.1"

Ответ 5

Лучше, если вы используете androidx.biometric.BiometricPrompt. Зависимость - это implementation 'androidx.biometric:biometric:1.0.0-alpha03'.

В BiometricPrompt указаны коды ошибок. Необходимо проверить, не является ли код ошибки в методе обратного вызова onAuthenticationError следующим образом:

BiometricConstants.ERROR_HW_NOT_PRESENT

Ответ 6

Метод - проверяет, что у пользователя включено разрешение на биометрическую аутентификацию для приложения, прежде чем использовать диспетчер пакетов для проверки доступности аутентификации по отпечатку пальца на устройстве. И даже он проверит, зарегистрирован ли пользователь или нет.

реализация 'androidx.biometric: biometric: 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;
}

Ответ 7

Доступен метод класса FingerprintManagerCompat.from(this).isHardwareDetected androidx.core.hardware.fingerprint.

Ответ 8

Для тех, кто не хочет ждать выпуска библиотеки поддержки, вы можете использовать ночные сборки следующим образом:

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'

получить версию сборки отсюда

https://ci.android.com/builds/branches/aosp-androidx-master-dev/

ветка aosp-androidx-master-dev

показать последнюю сборку из androidx-снимка