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

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

Требования:

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

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

Этапы создания этого метода соответствуют существующему процессу создания учетных данных . В вашем 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 в зависимости от ситуации. Они возвращают объекты, содержащие метаданные, необходимые поставщику. Например, при обработке выбора записи создания ключа доступа обновите свой код, как показано ниже:

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.authenitcationError
    // 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.authenitcationError
    // Process the error
}

  // Other logic...