Die APIs zur Übertragung von Anmeldedaten des Credential Manager ermöglichen die sichere Übertragung von Anmeldedaten zwischen Anmeldedatenanbietern auf demselben Gerät. In dieser Anleitung wird beschrieben
wie Anmeldedatenanbieter auf Android in die APIs der
androidx.credentials:providerevents-Bibliothek eingebunden werden können. Diese Funktion unterstützt
Passwörter, Passkeys, Adressinformationen und benutzerdefinierte Felder im
standardisierten FIDO Credential Exchange Format (CXF).
Wichtige Konzepte
Das Framework zur Übertragung von Anmeldedaten ermöglicht die Peer-to-Peer-Übertragung von Anmeldedaten auf demselben Gerät, ohne dass die Anmeldedaten im Rohformat an das Android-Betriebssystem oder nicht authentifizierte Apps weitergegeben werden.
Das Framework definiert zwei Hauptrollen:
- Exporter (Quellanbieter) : Ein Anmeldedatenanbieter, der derzeit Anmeldedaten von Nutzern enthält. Er registriert Metadaten zu verfügbaren exportierbaren
Konten (
ExportEntry) vorab beim System und reagiert auf Übertragungs anfragen, wenn er vom Nutzer ausgewählt wird. - Importer (Clientanbieter oder Einrichtungsassistent): Ein Anmeldedatenanbieter oder
Einrichtungsassistent, der eine Importanfrage initiiert
(
ImportCredentialsRequest) und angibt, welche Arten von Anmeldedaten und Erweiterungen er empfangen kann.
Android-Versionskompatibilität
Die Credentials Transfer API funktioniert auf Geräten mit Android 8 (API-Level 26) und höher.
Abhängigkeiten hinzufügen
Fügen Sie die Abhängigkeit androidx.credentials:providerevents zu
build.gradle oder build.gradle.kts Ihres Moduls hinzu:
dependencies {
implementation("androidx.credentials:providerevents:1.0.0-alpha06")
}
Erforderliche Klasse instanziieren
Erstellen Sie eine Instanz von ProviderEventsManager.
val providerEventsManager = ProviderEventsManager.create(context)
Exporter implementieren
Wenn Nutzer Anmeldedaten aus Ihrer App an andere Anmeldedatenanbieter auf dem Gerät exportieren sollen, implementieren Sie die Exporter-Rolle.
Exporteinträge registrieren
Wenn sich Ihr Anmeldedatenanbieter ändert (z. B. wenn sich ein Nutzer anmeldet, Anmeldedaten hinzufügt oder Konten ändert), registrieren oder aktualisieren Sie Ihre ExportEntry-Elemente mit ProviderEventsManager.registerExport().
Für jeden ExportEntry sind folgende Angaben erforderlich:
id: Ein geheimer, zufällig generierter String-Bezeichner, der diesen Exporteintrag eindeutig darstellt. Sie müssen diese ID sicher aufbewahren. Sie benötigen sie später, um eingehende Übertragungsanfragen zu bestätigen.accountDisplayName: Optionales Kontolabel (z. B."Personal Account").userDisplayName: Die primäre ID des Nutzers (z. B."alice@example.com").icon: EinBitmap-Symbol, das den Anbieter oder das Konto darstellt (wird von der Bibliothek automatisch auf 32 × 32 PNG skaliert).supportedCredentialTypes: Eine Reihe von Stringkonstanten ausCredentialTypes, die angeben, welche Typen dieser Eintrag enthält.
suspend fun registerMyProviderForExport( providerEventsManager: ProviderEventsManager, providerIcon: Bitmap, // Randomly generated and stored in encrypted storage secretEntryId: String ) { val entry = ExportEntry( id = secretEntryId, accountDisplayName = "MyProvider Personal", userDisplayName = "alice@example.com", icon = providerIcon, supportedCredentialTypes = setOf( CredentialTypes.CREDENTIAL_TYPE_BASIC_AUTH, // Passwords CredentialTypes.CREDENTIAL_TYPE_PUBLIC_KEY, // Passkeys CredentialTypes.CREDENTIAL_TYPE_ADDRESS, CredentialTypes.CREDENTIAL_TYPE_CREDIT_CARD ) ) // RegisterExportRequest.create() attaches the default WASM matcher from assets val request = RegisterExportRequest.create(context, listOf(entry)) try { val response = providerEventsManager.registerExport(request) // Registration successful } catch (e: Exception) { // Handle registration exceptions (e.g., RegisterExportProviderConfigurationException) } }
Exporter-Aktivität in der Manifestdatei deklarieren
Wenn der Nutzer Ihre ExportEntry in der Systemauswahl-UI auswählt, startet das System die von Ihnen festgelegte Activity zur Verarbeitung. Deklarieren Sie diese Activity mit der obligatorischen Intent-Aktion und dem Inhalts-URI-Schema:
<activity
android:name="com.example.CredentialExportActivity"
android:exported="true"
android:label="@string/export_activity_label">
<intent-filter>
// This intent action is required for Credential Manager to invoke this activity
<action android:name="androidx.identitycredentials.action.IMPORT_CREDENTIALS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
</intent-filter>
</activity>
Übertragungs-Intent in Ihrer Aktivität verarbeiten
Verwenden Sie in Ihrer CredentialExportActivity die Methode IntentHandler.retrieveProviderImportCredentialsRequest(intent), um die Anfrage zu parsen, die aufrufende App und credId zu bestätigen, die erforderliche biometrische Authentifizierung durchzuführen und die FIDO CXF-Nutzlast zurück in den angegebenen Content-URI zu schreiben:
class CredentialExportActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 1. Extract the transfer request from the incoming Intent val request: ProviderImportCredentialsRequest? = IntentHandler.retrieveProviderImportCredentialsRequest(intent) if (request == null) { finishWithError() return } // 2. Validate CallingAppInfo and secret `credId` val callingAppPackage = request.callingAppInfo.packageName val receivedCredId = request.credId if (!verifySecretEntryId(receivedCredId) || !isTrustedImporter(callingAppPackage)) { // Secret ID mismatch or untrusted caller -> abort sendExceptionAndFinish(ImportCredentialsNoExportOptionException("Unauthorized request")) return } // 3. Optional: Prompt user for Biometric / PIN authentication before exporting authenticateUserThenExport(request) } private fun authenticateUserThenExport(request: ProviderImportCredentialsRequest) { // ... Biometric prompt logic ... // Once authenticated, generate the FIDO CXF JSON string matching the requested types val cxfJsonPayload = buildFidoCxfJsonPayload( requestedTypes = request.request.credentialTypes, requestedExtensions = request.request.knownExtensions ) val response = ImportCredentialsResponse(cxfJsonPayload) // 4. Write the JSON payload to the Content URI and set Activity result IntentHandler.setImportCredentialsResponse( context = this, uri = request.uri, intent = intent, response = response ) setResult(Activity.RESULT_OK, intent) finish() } private fun sendExceptionAndFinish(exception: androidx.credentials.providerevents.exception.ImportCredentialsException) { IntentHandler.setImportCredentialsException(intent, exception) setResult(Activity.RESULT_OK, intent) finish() } private fun verifySecretEntryId(credentialId: String): Boolean { // Check if credentialId matches what you stored when calling RegisterExportRequest return credentialId == getStoredSecretEntryId() } private fun isTrustedImporter(packageName: String): Boolean { // Implement any specific allowlisting / caller checks if required return true } private fun finishWithError() { setResult(Activity.RESULT_CANCELED) finish() } }
Ausnahmen bei der Registrierung und Löschung von Exporten
Alle Ausnahmen in diesem Modul sind Unterklassen von
ImportCredentialsException, RegisterExportException, oder
ClearExportException.
RegisterExportProviderConfigurationExceptionoderClearExportProviderConfigurationException: Wird ausgelöst, wenn die Registrierung oder Löschung aufgrund von Problemen bei der Anbietereinrichtung fehlschlägt (z. B. leeresupportedCredentialTypesin einemExportEntry, oder Aufruf auf einer nicht unterstützten Betriebssystemebene).RegisterExportUnknownErrorExceptionoderClearExportUnknownErrorException: Beim Aktualisieren der Exportregistrierung ist ein nicht klassifizierter System- oder Speicher fehler aufgetreten.
Importer implementieren
Wenn Sie Anmeldedaten in Ihre App importieren möchten (z. B. während des Onboardings oder des Anbieter
imports), implementieren Sie die Importer-Rolle und initiieren Sie den Ablauf durch Aufrufen von
ProviderEventsManager.importCredentials().
Importanfrage erstellen und Ablauf starten
Geben Sie an, welche CredentialTypes und KnownExtensions Ihr Importer
unterstützt:
suspend fun startCredentialImport( activityContext: Context, providerEventsManager: ProviderEventsManager ) { val importRequest = ImportCredentialsRequest( credentialTypes = setOf( CredentialTypes.CREDENTIAL_TYPE_BASIC_AUTH, CredentialTypes.CREDENTIAL_TYPE_PUBLIC_KEY, CredentialTypes.CREDENTIAL_TYPE_ADDRESS, CredentialTypes.CREDENTIAL_TYPE_NOTE ), knownExtensions = setOf( KnownExtensions.KNOWN_EXTENSION_SHARED ) ) try { // Launches the system Selector UI; suspends until user selects a provider and completes transfer val response = providerEventsManager.importCredentials(activityContext, importRequest) // 1. Inspect the source exporter's package info val exporterPackageName = response.callingAppInfo.packageName // 2. Parse the FIDO CXF JSON string val cxfJsonString = response.response.responseJson parseAndSaveImportedCredentials(cxfJsonString) } catch (e: ImportCredentialsException) { // Handle specific import exceptions (e.g., ImportCredentialsCancellationException) handleImportFailure(e) } } private fun parseAndSaveImportedCredentials(cxfJsonString: String) { val rootJson = JSONObject(cxfJsonString) // Parse according to FIDO Credential Exchange Format (CXF v1.0) specification: // https://fidoalliance.org/specs/cx/cxf-v1.0-ps-20250814.html } // Helper function to make it compile private fun handleImportFailure(e: ImportCredentialsException) {}
Ausnahmen beim Importablauf
Alle Ausnahmen in diesem Modul sind Unterklassen von
ImportCredentialsException, RegisterExportException, oder
ClearExportException.
ImportCredentialsCancellationException: Der Nutzer hat die Auswahl-UI geschlossen oder die Exportaktivität abgebrochen (Activity.RESULT_CANCELED).ImportCredentialsNoExportOptionException: Es wurden keine registrierten Exporteinträge gefunden, die den angeforderten Anmeldedatentypen entsprechen, oder der ausgewählte Exporter hat eine Ausnahme für die Ablehnung ausgelöst.ImportCredentialsProviderConfigurationException: Konfigurationsfehler (z. B. leerecredentialTypesinImportCredentialsRequestoder fehlende Berechtigungen).ImportCredentialsInvalidJsonException: Der Exporter hat eine fehlerhafte oder leere JSON-Nutzlast zurückgegeben, bei der die Anfragenbestätigung fehlgeschlagen ist.ImportCredentialsSystemErrorException: Beim Import ist ein interner Android-System- oder Binder-Übertragungsfehler aufgetreten.ImportCredentialsUnknownCallerException: Die aufrufende App konnte vom Framework nicht bestätigt werden.ImportCredentialsUnknownErrorException: Nicht klassifizierter oder unerwarteter Fehler während des Importablaufs.
Unterstützte Anmeldedatentypen und Erweiterungen
Das Objekt androidx.credentials.providerevents.transfer.CredentialTypes definiert standardisierte Stringkonstanten, die den FIDO CXF-Elementtypen entsprechen:
| Konstante | Wert (cxf-Typ) |
Beschreibung |
|---|---|---|
CREDENTIAL_TYPE_BASIC_AUTH |
"basic-auth" |
Anmeldedaten für Nutzername und Passwort. |
CREDENTIAL_TYPE_PUBLIC_KEY |
"passkey" |
Öffentliche Schlüsselanmeldedaten für FIDO2 oder WebAuthn-Passkeys. |
CREDENTIAL_TYPE_ADDRESS |
"address" |
Informationen zur Post- oder Versandadresse für das automatische Ausfüllen von Formularen. |
CREDENTIAL_TYPE_API_KEY |
"api-key" |
API-Zugriffsschlüssel und -Tokens. |
CREDENTIAL_TYPE_CREDIT_CARD |
"credit-card" |
Zahlungsinformationen für Kredit- und Debitkarten. |
CREDENTIAL_TYPE_CUSTOM_FIELDS |
"custom-fields" |
Benutzerdefinierte Gruppierungen oder benutzerdefinierte Felder. |
CREDENTIAL_TYPE_DRIVERS_LICENSE |
"drivers-license" |
Führerscheindetails. |
CREDENTIAL_TYPE_FILE |
"file" |
Metadaten und Platzhalterreferenzen für Binärdateien. |
CREDENTIAL_TYPE_GENERATED_PASSWORD |
"generated-password" |
Maschinell generierte sichere Passwörter. |
CREDENTIAL_TYPE_IDENTITY_DOCUMENT |
"identity-document" |
Personalausweise, Sozialversicherungsnummern, Steuernummern oder Reisepassreferenzen. |
CREDENTIAL_TYPE_ITEM_REFERENCE |
"item-reference" |
Logische Links, die auf ein anderes Element in der Nutzlast verweisen. |
CREDENTIAL_TYPE_NOTE |
"note" |
Benutzerdefinierte sichere Notizen (UTF-8-String). |
CREDENTIAL_TYPE_PASSPORT |
"passport" |
Details zum Reisepass. |
CREDENTIAL_TYPE_PERSON_NAME |
"person-name" |
Details zur Identität und Namensgebung von Personen. |
CREDENTIAL_TYPE_SSH_KEY |
"ssh-key" |
Öffentliche und private SSH-Schlüsselpaare. |
CREDENTIAL_TYPE_TOTP |
"totp" |
Zeitbasierte Einmalpasswörter (2FA). |
CREDENTIAL_TYPE_WIFI |
"wifi" |
WLAN-SSID und Passphrasen. |
Benutzerdefinierte WASM-Matcher (WebAssembly) (erweitert)
Standardmäßig wird beim Aufrufen von RegisterExportRequest.create(context, entries) die systemseitige credential_transfer_matcher.wasm aus den Bibliotheksassets gebündelt, die Einträge ausschließlich anhand der Schnittmenge von supportedCredentialTypes filtert.
Wenn Ihr Anmeldedatenanbieter eine komplexe Abgleichslogik erfordert (z. B. dynamische Überprüfungen der Funktionen oder bedingtes Filtern basierend auf benutzerdefinierten Feldern), können Sie Ihr eigenes WebAssembly-Modul kompilieren, das der WASM-API zur Übertragung von Anmeldedaten entspricht, und das Roh-Byte-Array direkt übergeben:
// Loading a custom WASM matcher val customMatcherBytes = context.assets.open("my_custom_matcher.wasm").use { it.readBytes() } val customRequest = RegisterExportRequest( entries = myEntries, exportMatcher = customMatcherBytes ) providerEventsManager.registerExport(customRequest)