رابطهای برنامهنویسی کاربردی (API) انتقال اعتبارنامهها (Credentials Transfer) در Credential Manager، انتقال امن و یکسان اعتبارنامههای کاربر بین ارائهدهندگان اعتبارنامه را در یک دستگاه امکانپذیر میکنند. این راهنما به تفصیل توضیح میدهد که چگونه ارائهدهندگان اعتبارنامه در اندروید میتوانند با APIهای ارائه شده توسط کتابخانه androidx.credentials:providerevents ادغام شوند. این ویژگی از رمزهای عبور، کلیدهای عبور، اطلاعات آدرس و فیلدهای سفارشی با استفاده از قالب استاندارد تبادل اعتبارنامه FIDO (CXF) پشتیبانی میکند.
مفاهیم اصلی
چارچوب انتقال اعتبارنامه، انتقال اعتبارنامه همتا به همتا را در همان دستگاه بدون افشای اعتبارنامههای خام به سیستم عامل اندروید یا برنامههای احراز هویت نشده، تسهیل میکند.
این چارچوب دو نقش اصلی را تعریف میکند:
- صادرکننده (ارائهدهنده منبع): یک ارائهدهنده اعتبارنامه که در حال حاضر اعتبارنامههای کاربر را در اختیار دارد. این ارائهدهنده، فرادادههای مربوط به حسابهای قابل صدور موجود (
ExportEntry) را از قبل در سیستم ثبت میکند و در صورت انتخاب توسط کاربر، به درخواستهای انتقال پاسخ میدهد. - واردکننده (ارائهدهنده سرویس گیرنده یا ویزارد راهاندازی): یک ارائهدهنده اعتبارنامه یا ویزارد راهاندازی که یک درخواست واردات (
ImportCredentialsRequest) را آغاز میکند و مشخص میکند چه نوع اعتبارنامهها و افزونههایی را میتواند دریافت کند.
سازگاری با نسخه اندروید
رابط برنامهنویسی کاربردی انتقال اعتبارنامهها (Credentials Transfer API) روی دستگاههایی که اندروید ۸ (سطح API 26) و بالاتر را اجرا میکنند، کار میکند.
وابستگیها را اضافه کنید
وابستگی androidx.credentials:providerevents به build.gradle یا build.gradle.kts ماژول خود اضافه کنید:
dependencies {
implementation("androidx.credentials:providerevents:1.0.0-alpha06")
}
Instantiate the required class
یک نمونه از ProviderEventsManager مورد نیاز ایجاد کنید.
val providerEventsManager = ProviderEventsManager.create(context)
پیادهسازی صادرکننده
برای اینکه کاربران بتوانند اعتبارنامهها را از برنامه شما به سایر ارائهدهندگان اعتبارنامه در دستگاه صادر کنند، نقش صادرکننده را پیادهسازی کنید.
ثبت ورودیهای صادراتی
وقتی ارائهدهندهی اعتبارنامهی شما تغییر میکند (برای مثال، کاربری وارد سیستم میشود، اعتبارنامه اضافه میکند یا حسابها را تغییر میدهد)، آیتمهای ExportEntry خود را با استفاده از ProviderEventsManager.registerExport() ثبت یا بهروزرسانی کنید.
هر ExportEntry نیاز دارد به:
-
id: یک شناسه رشتهای مخفی و تصادفی که منحصراً نمایانگر این ورودی خروجی است. شما باید این شناسه را به طور ایمن ذخیره کنید ؛ بعداً برای تأیید درخواستهای انتقال ورودی به آن نیاز خواهید داشت. -
accountDisplayName: برچسب حساب اختیاری (برای مثال،"Personal Account"). -
userDisplayName: شناسه اصلی کاربر (برای مثال،"alice@example.com"). -
icon: یک آیکونBitmapکه نشاندهندهی ارائهدهنده یا حساب کاربری است (بهطور خودکار توسط کتابخانه به PNG 32x32 مقیاسبندی میشود). -
supportedCredentialTypes: مجموعهای از ثابتهای رشتهای ازCredentialTypesکه نشان میدهند این ورودی چه نوعهایی را در خود جای میدهد.
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) } }
فعالیت صادرکننده را در فایل مانیفست اعلام کنید
وقتی کاربر ExportEntry شما را در رابط کاربری انتخابگر سیستم انتخاب میکند، سیستم Activity مربوط به مدیریت تعیینشده شما را اجرا میکند. این activity را با intent اجباری action و content URI scheme تعریف کنید:
<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>
مدیریت قصد انتقال در اکتیویتی شما
در CredentialExportActivity خود، از IntentHandler.retrieveProviderImportCredentialsRequest(intent) برای تجزیه درخواست، تأیید برنامه فراخوانی و credId ، انجام هرگونه احراز هویت بیومتریک مورد نیاز و نوشتن payload FIDO CXF در URI محتوای ارائه شده استفاده کنید:
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() } }
استثنائات ثبت و ترخیص صادرات
All exceptions in this module are subclasses of ImportCredentialsException , RegisterExportException , or ClearExportException .
-
RegisterExportProviderConfigurationExceptionیاClearExportProviderConfigurationException: زمانی رخ میدهد که ثبت یا پاکسازی به دلیل مشکلات راهاندازی ارائهدهنده (برای مثال، خالی بودنsupportedCredentialTypesدرExportEntryیا فراخوانی یک لایه سیستمعامل پشتیبانی نشده) با شکست مواجه شود. -
RegisterExportUnknownErrorExceptionorClearExportUnknownErrorException: Unclassified system or storage error occurred while updating the export registry.
واردکننده را پیادهسازی کنید
برای وارد کردن اعتبارنامهها به برنامه خود (برای مثال، در طول فرآیند نصب یا وارد کردن ارائهدهنده)، نقش واردکننده را پیادهسازی کنید و جریان را با فراخوانی ProviderEventsManager .importCredentials() آغاز کنید.
ساخت درخواست واردات و جریان راهاندازی
مشخص کنید که واردکننده شما از کدام CredentialTypes و KnownExtensions پشتیبانی میکند:
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) {}
استثنائات جریان واردات
تمام استثنائات در این ماژول، زیرکلاسهای ImportCredentialsException ، RegisterExportException یا ClearExportException هستند.
-
ImportCredentialsCancellationException: کاربر رابط کاربری انتخابگر را رد کرد یا فعالیت export (Activity.RESULT_CANCELED) را لغو کرد. -
ImportCredentialsNoExportOptionException: هیچ ورودی اکسپورت ثبتشدهای با انواع اعتبارنامههای درخواستی مطابقت نداشت، یا اکسپورتکنندهی انتخابشده یک استثنای رد صادر کرد. -
ImportCredentialsProviderConfigurationException: خطای پیکربندی (برای مثال،credentialTypesخالی درImportCredentialsRequestتنظیم شده یا مجوزهای آن وجود ندارد). -
ImportCredentialsInvalidJsonException: The exporter returned a malformed or empty JSON payload that failed request validation. -
ImportCredentialsSystemErrorException: خطای انتقال داخلی سیستم اندروید یا Binder هنگام وارد کردن رخ داده است. -
ImportCredentialsUnknownCallerException: برنامهی فراخوانی توسط فریمورک قابل تأیید نیست. -
ImportCredentialsUnknownErrorException: خطای طبقهبندی نشده یا غیرمنتظره در جریان واردات.
Supported credential types and extensions
شیء androidx.credentials.providerevents.transfer.CredentialTypes ثابتهای رشتهای استاندارد مربوط به انواع آیتمهای FIDO CXF را تعریف میکند:
| ثابت | مقدار (نوع cxf ) | توضیحات |
|---|---|---|
CREDENTIAL_TYPE_BASIC_AUTH | "basic-auth" | اطلاعات ورود به سیستم با نام کاربری و رمز عبور. |
CREDENTIAL_TYPE_PUBLIC_KEY | "passkey" | اعتبارنامههای کلید عمومی رمز عبور FIDO2 یا WebAuthn. |
CREDENTIAL_TYPE_ADDRESS | "address" | اطلاعات آدرس پستی یا حمل و نقل برای تکمیل خودکار فرم. |
CREDENTIAL_TYPE_API_KEY | "api-key" | کلیدها و توکنهای دسترسی API. |
CREDENTIAL_TYPE_CREDIT_CARD | "credit-card" | اطلاعات پرداخت با کارت اعتباری و بدهی. |
CREDENTIAL_TYPE_CUSTOM_FIELDS | "custom-fields" | Custom groupings or user-defined fields. |
CREDENTIAL_TYPE_DRIVERS_LICENSE | "drivers-license" | جزئیات گواهینامه رانندگی. |
CREDENTIAL_TYPE_FILE | "file" | ارجاعات فراداده و جاینگهدار برای فایلهای باینری. |
CREDENTIAL_TYPE_GENERATED_PASSWORD | "generated-password" | Machine-generated secure passwords. |
CREDENTIAL_TYPE_IDENTITY_DOCUMENT | "identity-document" | National ID cards, SSN, TIN, or passport references. |
CREDENTIAL_TYPE_ITEM_REFERENCE | "item-reference" | پیوندهای منطقی که به مورد دیگری در payload اشاره میکنند. |
CREDENTIAL_TYPE_NOTE | "note" | یادداشتهای امن تعریفشده توسط کاربر (رشته UTF-8). |
CREDENTIAL_TYPE_PASSPORT | "passport" | جزئیات سند مسافرتی گذرنامه. |
CREDENTIAL_TYPE_PERSON_NAME | "person-name" | هویت شخص و جزئیات نامگذاری. |
CREDENTIAL_TYPE_SSH_KEY | "ssh-key" | جفت کلیدهای عمومی و خصوصی SSH |
CREDENTIAL_TYPE_TOTP | "totp" | رمزهای عبور یکبار مصرف (2FA) مبتنی بر زمان. |
CREDENTIAL_TYPE_WIFI | "wifi" | SSID و رمز عبور شبکه Wi-Fi. |
تطبیقدهندههای سفارشی WASM (WebAssembly) (پیشرفته)
به طور پیشفرض، فراخوانی RegisterExportRequest.create(context, entries) فایل پیشفرض سیستم credential_transfer_matcher.wasm را از داراییهای کتابخانهای دسته میکند، که ورودیها را صرفاً بر اساس اشتراک supportedCredentialTypes فیلتر میکند.
اگر ارائهدهندهی اعتبارنامهی شما به منطق تطبیق پیچیدهای نیاز دارد (برای مثال، بررسیهای قابلیت پویا یا فیلترینگ شرطی بر اساس فیلدهای سفارشی)، میتوانید ماژول WebAssembly خود را که با API انتقال اعتبارنامهی WASM مطابقت دارد، کامپایل کنید و آرایهی بایت خام را مستقیماً ارسال کنید:
// 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)