Интегрируйте создание ключа доступа одним касанием и вход в систему с биометрическими подсказками.

В Android 15 Credential Manager поддерживает создание и извлечение учётных данных одним касанием. В этом случае информация о создаваемых или используемых учётных данных отображается непосредственно в биометрическом запросе, а также предоставляет доступ к дополнительным опциям. Этот упрощённый процесс делает создание и извлечение учётных данных более эффективным и оптимизированным.

Требования:

  • На устройстве пользователя настроена биометрия, и пользователь разрешает ей аутентификацию в приложениях.
  • Для потоков входа эта функция доступна только для сценариев с одной учетной записью, даже если для этой учетной записи доступно несколько учетных данных (например, ключ доступа и пароль).

Включить одно нажатие для создания ключа доступа

Этапы создания этого метода соответствуют существующему процессу создания учётных данных . В запросе BeginCreatePublicKeyCredentialRequest используйте handleCreatePasskeyQuery() для обработки запроса, если он предназначен для ключа доступа.

is BeginCreatePublicKeyCredentialRequest -> {
    Log.i(TAG, "Request is passkey type")
    return handleCreatePasskeyQuery(request, passwordCount, passkeyCount)
}

В handleCreatePasskeyQuery() включите BiometricPromptData с классом CreateEntry :

val createEntry = CreateEntry(
    // Additional properties...
    biometricPromptData = BiometricPromptData(
        allowedAuthenticators = allowedAuthenticator
    ),
)

Поставщики учётных данных должны явно задать свойство allowedAuthenticator в экземпляре BiometricPromptData . Если это свойство не задано, по умолчанию используется значение DEVICE_WEAK . При необходимости задайте необязательное свойство cryptoObject .

Включить одиночное нажатие для потоков ввода ключа доступа

Подобно процессу создания ключа доступа, он будет соответствовать существующей настройке обработки входа пользователя . В параметре BeginGetPublicKeyCredentialOption используйте populatePasskeyData() для сбора необходимой информации о запросе аутентификации:

is BeginGetPublicKeyCredentialOption -> {
    // ... other logic

    populatePasskeyData(
        origin,
        option,
        responseBuilder,
        autoSelectEnabled,
        allowedAuthenticator
    )

    // ... other logic as needed
}

Аналогично CreateEntry , экземпляр BiometricPromptData устанавливается в качестве экземпляра PublicKeyCredentialEntry . Если явно не указано иное, allowedAuthenticator по умолчанию принимает значение BIOMETRIC_WEAK .

PublicKeyCredentialEntry(
    // other properties...

    biometricPromptData = BiometricPromptData(
        allowedAuthenticators = allowedAuthenticator
    )
)

Выбор ввода учетных данных

При обработке выбора записи учётных данных для создания ключа доступа или выбора ключа доступа во время входа в систему вызовите PendingIntentHandler's retrieveProviderCreateCredentialRequest или retrieveProviderGetCredentialRequest объекта PendingIntentHandler, в зависимости от ситуации. Они возвращают объекты, содержащие метаданные, необходимые поставщику. Например, при обработке выбора записи для создания ключа доступа обновите код, как показано ниже:

val createRequest = PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
if (createRequest == null) {
    Log.i(TAG, "request is null")
    setUpFailureResponseAndFinish("Unable to extract request from intent")
    return
}
// Other logic...

val biometricPromptResult = createRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (createRequest.callingRequest is CreatePublicKeyCredentialRequest) {
    val publicKeyRequest: CreatePublicKeyCredentialRequest =
        createRequest.callingRequest as CreatePublicKeyCredentialRequest

    if (biometricPromptResult == null) {
        // Do your own authentication flow, if needed
    }
    else if (biometricPromptResult.isSuccessful) {
        createPasskey(
            publicKeyRequest.requestJson,
            createRequest.callingAppInfo,
            publicKeyRequest.clientDataHash,
            accountId
        )
    } else {
        val error = biometricPromptResult.authenticationError
        // Process the error
    }

    // Other logic...
}

В этом примере содержится информация об успешности биометрического потока. Он также содержит другую информацию об учётных данных. В случае сбоя потока используйте код ошибки из biometricPromptResult.authenticationError для принятия решений. Коды ошибок, возвращаемые в рамках biometricPromptResult.authenticationError.errorCode , совпадают с кодами ошибок, определёнными в библиотеке androidx.biometric, такими как androidx.biometric.BiometricPrompt.NO_SPACE , androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS , androidx.biometric.BiometricPrompt.ERROR_TIMEOUT и аналогичными. Ошибка authenticationError также будет содержать сообщение об ошибке, связанное с errorCode , которое может быть отображено в пользовательском интерфейсе.

Аналогичным образом извлеките метаданные во время retrieveProviderGetCredentialRequest . Проверьте, равен ли ваш биометрический поток null . Если да, настройте собственную биометрию для аутентификации. Это похоже на инструментирование операции get :

val getRequest =
    PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)

if (getRequest == null) {
    Log.i(TAG, "request is null")
    setUpFailureResponseAndFinish("Unable to extract request from intent")
    return
}

// Other logic...

val biometricPromptResult = getRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (biometricPromptResult == null)
{
    // Do your own authentication flow, if necessary
} else if (biometricPromptResult.isSuccessful) {

    Log.i(TAG, "The response from the biometricPromptResult was ${biometricPromptResult.authenticationResult?.authenticationType}")

    validatePasskey(
        publicKeyRequest.requestJson,
        origin,
        packageName,
        uid,
        passkey.username,
        credId,
        privateKey
    )
} else {
    val error = biometricPromptResult.authenticationError
    // Process the error
}

// Other logic...