> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK أندرويد Kotlin للتحقق من الهوية و KYC

> SDK أندرويد Kotlin من Didit للتحقق من الهوية وكشف الحيوية وقراءة NFC لجوازات السفر. من $0.33 لكل فحص KYC كامل، و$10 مجاناً شهرياً، دون عقود.



موجّه تكامل Android SDK
        نسخ الموجّه إلى الحافظة



      
      

\<pre>

\`Integrate Didit identity verification into my Android app using the native Kotlin SDK.

\## Requirements
\- Android API 23+ (Android 6.0 Marshmallow). ML-based auto-detection (document/face) requires API 24+ and falls back to manual capture below that.
\- Kotlin 1.9+
\- NFC reading requires NFC-capable device hardware

\## Installation

\### Step 1: Add Maven Repository
In settings.gradle.kts:
dependencyResolutionManagement {
repositories {
    google()
    mavenCentral()
    maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
}
}

\### Step 2: Add Dependency
(!) Regarding the version ensure you check the [GitHub repository](https://github.com/didit-protocol/sdk-android) for the latest version.
In app/build.gradle.kts:
dependencies {
implementation("me.didit:didit-sdk:4.13.2")
}

\### Step 3: Add Packaging Exclusion (required to avoid build conflicts)
In the android { } block of app/build.gradle.kts:
android {
packaging {
    resources {
        excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
    }
}
}

\## Permissions (auto-merged from SDK manifest)
\- INTERNET (required) — API communication
\- ACCESS_NETWORK_STATE (required) — Network availability
\- CAMERA (required) — Document scanning and face verification
\- NFC (optional) — Read NFC chips in passports/IDs

Camera and NFC are declared as optional features (android:required="false"), so the app installs on all devices.

\## Initialization (required)
In your Application class:
import me.didit.sdk.DiditSdk

class MyApp : Application() {
override fun onCreate() {
    super.onCreate()
    DiditSdk.initialize(this)
}
}

Register in AndroidManifest.xml:
\<application android:name=".MyApp" ...>

\## Backend: Create Session (your server)
POST https://verification.didit.me/v3/session/
Headers: { "x-api-key": DIDIT_API_KEY, "Content-Type": "application/json" }
Body: { "workflow_id": DIDIT_WORKFLOW_ID, "vendor_data": "user-id" }
Response: { "session_id": "uuid", "session_token": "short-token", "url": "https://verify.didit.me/session/short-token", "status": "Not Started" }
Send session_token to the Android app (never expose DIDIT_API_KEY to the device).

\## Jetpack Compose Integration
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

// Observe SDK state and launch UI when ready
LaunchedEffect(Unit) {
DiditSdk.state.collect { state ->
    when (state) {
        is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(activity)
        is DiditSdkState.Error -> Log.e("Didit", "Error: state.message")
        else -> { /* Loading, Idle, CreatingSession */ }
    }
}
}

// Start verification with session token from backend
import me.didit.sdk.VerificationStatus

fun startVerification(token: String) {
DiditSdk.startVerification(token = token) { result ->
    when (result) {
        is VerificationResult.Completed -> when (result.session.status) {
            VerificationStatus.APPROVED -> { /* grant access */ }
            VerificationStatus.DECLINED -> { /* show retry */ }
            VerificationStatus.PENDING  -> { /* under review */ }
        }
        is VerificationResult.Cancelled -> { /* user cancelled */ }
        is VerificationResult.Failed    -> { /* show error: result.error.message */ }
    }
}
}

\## Result Statuses (VerificationStatus enum; .rawValue gives "Approved" / "Pending" / "Declined")
\- VerificationStatus.APPROVED — user identity verified, grant access
\- VerificationStatus.DECLINED — verification failed, show retry or contact support
\- VerificationStatus.PENDING  — needs manual review by your compliance team

\## Full Verification Results
The SDK only returns the status. Full decision data (document fields, face match scores, AML hits, etc.) arrives via webhook to your backend.
Set up webhooks: https://docs.didit.me/integration/webhooks

\## Rate Limits (session creation)
\- 600 session-create requests / minute per x-api-key (see https://docs.didit.me/integration/rate-limiting)
\- On 429, retry honouring Retry-After / X-RateLimit-* headers

\## Environment Variables (backend only — never expose in the Android app)
\- DIDIT_API_KEY — from Didit Console > API & Webhooks
\- DIDIT_WORKFLOW_ID — from Didit Console > Workflows

\## Docs
\- Android SDK: https://docs.didit.me/integration/native-sdks/android-sdk
\- GitHub: https://github.com/didit-protocol/sdk-android
\- Webhooks: https://docs.didit.me/integration/webhooks
\- API Reference: https://docs.didit.me/api-reference/overview`

\</pre>



      
      

الصق في

حزمة SDK خفيفة لنظام Android تعتمد على الخادم في عملها، وتتطلب حدًا أدنى من الإعداد للتحقق من الهوية.> [card] [مستودع GitHub](https://github.com/didit-protocol/sdk-android)
>
> اطّلع على الشيفرة المصدرية والأمثلة على GitHub> [!NOTE]
>
> ### **حزمة SDK الأصلية**: هذا هو النهج الموصى به لتطبيقات Android. توفر حزم SDK الأصلية أفضل تجربة للمستخدم، ومعالجة محسّنة للكاميرا، ودعمًا كاملًا لـ NFC.***## المتطلبات| المتطلب | الحد الأدنى للإصدار |
| - | - |
| Android API | 23+ (Android 6.0 Marshmallow). يتطلب الكشف التلقائي باستخدام ML الإصدار 24+ من API (انظر أدناه). |
| Kotlin | 1.9+ |
| Jetpack Compose | مضمّن كتبعية متعدية |> [!NOTE]
>
> **توفر الميزات حسب مستوى API**: يتطلب الكشف التلقائي عن المستند والوجه المستوى 24+ من API (أدوات الكشف الخفيفة الخاصة بـ Didit، والمضمّنة في `didit-sdk-core`). على أجهزة API 23 يعود SDK إلى الالتقاط اليدوي مع زر تصوير مؤقت. تعمل كل الميزات الأخرى عبر النطاق الكامل من API 23+.> [!NOTE]
>
> **تتطلب الموافقة البيومترية الإصدار 4.10.0 أو أحدث من SDK الأصلي.** بالنسبة للأشخاص الخاضعين لقوانين ولاية Illinois أو Texas أو Colorado، يمكن لـ Didit أن تطلب [الموافقة البيومترية](https://docs.didit.me/ar/getting-started/biometric-consent.md) الصريحة قبل أول التقاط للوجه. يعرض Android SDK الإصدار 4.10.0 وما بعده هذه الخطوة. لا تستطيع الإصدارات الأقدم عرضها: تعمل جلساتها كما كانت من قبل، ويُبلّغ القرار بأن الموافقة لم تُجمع (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). قم بالترقية إذا كنت تتحقق من أشخاص في تلك الولايات.***## التثبيت### الخطوة 1: إضافة المستودعأضف مستودع Maven الخاص بـ Didit إلى كتلة `repositories` في ملف `settings.gradle.kts` لديك:```kotlin theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}
```أو إذا كنت تستخدم `settings.gradle` (Groovy):```groovy theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}
```### الخطوة 2: إضافة التبعيةأضف تبعية SDK إلى ملف `build.gradle.kts` الخاص بتطبيقك:
(!) فيما يخص الإصدار، تأكد من مراجعة [مستودع GitHub](https://github.com/didit-protocol/sdk-android) للاطلاع على أحدث إصدار.```kotlin theme={null}
dependencies {
    implementation("me.didit:didit-sdk:4.13.2")
}
```أو إذا كنت تستخدم `build.gradle` (Groovy):```groovy theme={null}
dependencies {
    implementation "me.didit:didit-sdk:4.13.2"
}
```#### أنواع حزم SDKيأتي Android SDK في شكل حزم منفصلة، لذا لا يتحمّل تطبيقك تكلفة الحجم الثنائي إلا للميزات التي يستخدمها. الحزمة `me.didit:didit-sdk` أعلاه هي الحزمة الكاملة. اختر الحزمة المناسبة لتطبيقك:| الحزمة | الكشف التلقائي (ML) | قراءة شريحة NFC | استخدمها عندما |
| - | :-: | :-: | - |
| `me.didit:didit-sdk-core` | ✓ | – | أصغر بناء؛ التقاط تلقائي باستخدام أدوات الكشف الخاصة بـ Didit، دون قراءة شريحة جواز السفر أو الهوية |
| `me.didit:didit-sdk-autodetection` | ✓ | – | مهملة وفارغة منذ 4.11.0؛ تعتمد على `didit-sdk-core` فقط، لذا استخدم `didit-sdk-core` بدلاً منها |
| `me.didit:didit-sdk-nfc` | ✓ | ✓ | قراءة الشريحة بالإضافة إلى `didit-sdk-core` |
| `me.didit:didit-sdk` | ✓ | ✓ | كل الميزات (الحزمة الكاملة) |منذ الإصدار `4.6.0`، أصبح توقيع المحافظ الأصلي عبر WalletConnect يتوفر كإضافة اختيارية مستقلة، هي `me.didit:didit-sdk-wallet`.
تتضمنها حزمة `me.didit:didit-sdk` الكاملة بالفعل، لذا لن يتغير شيء إذا ثبّتّ الحزمة الكاملة.
إذا كنت تستخدم إحدى الحزم الأخف وتريد أن يتم تأكيد ملكية المحفظة بشكل أصلي داخل تطبيقك، فأضف `me.didit:didit-sdk-wallet` بجانبها. ومن دون هذه الإضافة يُكمل SDK تأكيد ملكية المحفظة عبر مسار متصفح آمن، فتبقى الميزة تعمل في الحالتين.
كما أدى نقل WalletConnect خارج `didit-sdk-core` إلى إزالة عدة ميغابايتات من تبعيات المحافظ من كل بناء لا يحتاجها.جميع الحزم منشورة بالإصدار نفسه، لذا أبقها على `4.13.2`.#### الحفاظ على صغر حجم التنزيلتُنزَّل نماذج الكشف المستخدمة في الالتقاط التلقائي أثناء التشغيل وتُخزَّن مؤقتاً، لذلك لا تُحتسب أبداً ضمن حجم تطبيقك.
ما يضيفه الالتقاط التلقائي إلى تطبيقك هو المكتبة الأصلية لبيئة تشغيل ML، وهذه التكلفة تختلف حسب معمارية المعالج: تقريباً 10 MB لـ `arm64-v8a`، و7 MB لـ `armeabi-v7a`، و13 MB لكل واحدة من معماريتي محاكيات x86.لتتحمّل هذه التكلفة مرة واحدة فقط:1) **انشر Android App Bundle (AAB).** يسلّم Google Play للجهاز معماريته ولغاته فقط، فيثبّت هاتف arm64 نحو 10 MB من الشيفرة الأصلية (حوالي 4 MB بعد الضغط). أما APK العام فيحزم المعماريات الأربع كلها، بحجم إجمالي يتجاوز 40 MB، وهذا هو السبب الأكثر شيوعاً لقياسات الحجم الكبيرة غير المتوقعة.
2) **إذا وزّعت APK واحداً** وكان جمهورك من هواتف وأجهزة لوحية ARM، فقيّد المعماريات المضمّنة:

   ```kotlin theme={null}
   android {
       defaultConfig {
           ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
       }
   }
   ```

   أبقِ كل ABI يشغّله مستخدموك فعلاً. أضف `x86_64` إذا كنت تستهدف أجهزة Chromebook أو أجهزة x86 أخرى، أو انشر تقسيمات APK لكل ABI حتى لا يفقد أي جهاز الدعم.
3) **فعّل R8**: اضبط `isMinifyEnabled = true` و`isShrinkResources = true` في نوع بناء الإصدار (`minifyEnabled true` و`shrinkResources true` إذا كنت تستخدم Groovy `build.gradle`). يأتي SDK مع قواعد المستهلك الخاصة به، لذا تُحذف شيفرة SDK غير المستخدمة من دون أي إعداد إضافي.
4) **حدّ اللغات المضمّنة** باستخدام `resConfigs(...)` إذا لم تكن بحاجة إلى جميع الإعدادات المحلية الـ48 الخاصة بـ SDK في بناء APK. تتولى تقسيمات اللغات في AAB هذا الأمر تلقائياً على Google Play.### الخطوة 3: إضافة استثناء للتغليفأضف هذا إلى كتلة `android` في تطبيقك لتجنب تعارضات البناء:```kotlin theme={null}
android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}
```هذا كل شيء! سيحلّ Gradle جميع التبعيات المتعدية تلقائياً.***## الأذوناتيطلب الـSDK الأذونات التالية. يُصرَّح بها في ملف `AndroidManifest.xml` الخاص بالـSDK، وستُدمج تلقائياً في ملف البيان (manifest) في تطبيقك:| الإذن | مصدر AAR | الوصف | مطلوب |
| - | - | - | - |
| `INTERNET` | `didit-sdk-core` | الوصول إلى الشبكة للتواصل مع الواجهة البرمجية | نعم |
| `ACCESS_NETWORK_STATE` | `didit-sdk-core` | رصد توفر الشبكة | نعم |
| `CAMERA` | `didit-sdk-core` | مسح المستندات والتحقق من الوجه | نعم |
| `NFC` | `didit-sdk-nfc` | قراءة شرائح NFC في جوازات السفر وبطاقات الهوية | يُدمج تلقائياً من `didit-sdk-nfc` (اعتمادية متعدية لـ `me.didit:didit-sdk`) |### ميزات الكاميرا وNFCيُصرّح الـSDK بالميزتين `android.hardware.camera` و`android.hardware.nfc` بوصفهما ميزتين اختياريتين (`android:required="false"`). يتيح ذلك تثبيت تطبيقك على الأجهزة التي لا تحتوي على كاميرا أو على عتاد NFC، إذ يتعامل الـSDK مع غياب العتاد أثناء التشغيل بسلاسة.***## البدء السريع### الخطوة 1: تهيئة الـSDKهيّئ الـSDK داخل `Application.onCreate()`:```kotlin theme={null}
import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}
```### الخطوة 2: بدء التحقق والتعامل مع النتائج```kotlin theme={null}
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state to launch UI when ready
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Loading, Idle, CreatingSession */ }
                }
            }
        }
    }

    private fun startVerification() {
        // Method 1: UniLink (no backend required)
        DiditSdk.startVerification(
            workflowId = "your-workflow-id",
            vendorData = "user-123"
        ) { result ->
            handleResult(result)
        }

        // Method 2: Backend Session (recommended for production)
        // DiditSdk.startVerification(
        //     token = "your-session-token"
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                Log.d("Didit", "Session: ${result.session.sessionId}")
                Log.d("Didit", "Status: ${result.session.status}")
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "User cancelled")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Failed: ${result.error.message}")
            }
        }
    }
}
```***## طرق التكامليدعم الـSDK طريقتين للتكامل:### الطريقة 1: UniLink (الأبسط)لا يتطلب خادماً خلفياً. يُنشئ الـSDK الجلسة مباشرةً باستخدام معرّف سير العمل (workflow ID) من Didit Console. وهي محصورة في `vendorData` فقط.```kotlin theme={null}
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"
) { result ->
    handleResult(result)
}
```### الطريقة 2: الجلسة من الخادم الخلفي (موصى بها للإنتاج)ينشئ خادمك الخلفي الجلسة عبر [واجهة برمجة تطبيقات إنشاء جلسة التحقق](https://docs.didit.me/ar/sessions-api/create-session.md) (`POST /v3/session/`) مع دعم كامل للمعاملات (`contact_details` و`expected_details` و`metadata` و`callback` وغيرها)، ثم يمرر `session_token` إلى الـSDK.```kotlin theme={null}
// Your backend creates a session and returns the token
val sessionToken = yourBackend.createVerificationSession(userId = currentUser.id)

// Pass the token to the SDK
DiditSdk.startVerification(
    token = sessionToken
) { result ->
    handleResult(result)
}
```يمنحك هذا النهج تحكماً كاملاً في:- ربط الجلسات بمستخدميك (`vendor_data`)
- تعيين بيانات وصفية مخصصة
- ضبط عمليات الاستدعاء الخاصة بكل جلسة
- توفير تفاصيل الاتصال والتفاصيل المتوقعة للتحقق المتقاطع***## الإعداداتخصّص سلوك الـSDK:```kotlin theme={null}
import me.didit.sdk.Configuration
import me.didit.sdk.core.localization.SupportedLanguage

val configuration = Configuration(
    languageLocale = SupportedLanguage.SPANISH,  // Force Spanish language
    showLanguageSelector = true,                  // Let the user change language
    fontFamily = "my_custom_font",                // Custom font (must be in res/font/)
    loggingEnabled = true                         // Enable debug logging
)

DiditSdk.startVerification(
    token = "your-session-token",
    configuration = configuration
) { result ->
    handleResult(result)
}
```### خيارات الإعدادات| الخاصية | النوع | القيمة الافتراضية | الوصف |
| - | - | - | - |
| `languageLocale` | `SupportedLanguage?` | لغة الجهاز | فرض لغة محددة |
| `showLanguageSelector` | `Boolean` | `false` | إظهار محدد اللغة بنمط الويب في شاشة الترحيب |
| `fontFamily` | `String?` | خط النظام | اسم مورد الخط المخصص (من `res/font/`) |
| `loggingEnabled` | `Boolean` | `false` | تفعيل تسجيل التصحيح الخاص بالـSDK |
| `showCloseButton` | `Boolean` | `true` | إظهار زر الإغلاق (X) في شاشات خطوات التحقق |
| `showExitConfirmation` | `Boolean` | `true` | إظهار مربع حوار التأكيد عندما يحاول المستخدم الخروج |
| `closeOnComplete` | `Boolean` | `false` | إغلاق واجهة التحقق تلقائياً عند الاكتمال (المكافئ في Web SDK: `closeModalOnComplete`) |
| `defaultDocumentCamera` | `CameraLens` | `CameraLens.BACK` | العدسة المستخدمة عند فتح شاشة التقاط المستند |
| `defaultLivenessCamera` | `CameraLens` | `CameraLens.FRONT` | العدسة المستخدمة عند فتح شاشة التقاط الوجه (الحيوية) |
| `showDocumentCameraSwitchButton` | `Boolean` | `true` | إظهار مبدّل الكاميرا أثناء الالتقاط في شاشة التقاط المستند |
| `showLivenessCameraSwitchButton` | `Boolean` | `true` | إظهار مبدّل الكاميرا أثناء الالتقاط في شاشة التقاط الوجه |### خيارات الكاميراتتوافق خيارات الكاميرا مع [خيارات كاميرا Web SDK](https://docs.didit.me/ar/integration/web-sdks/javascript-sdk.md#خيارات-الكاميرا).
كل عدسة هي إما `CameraLens.FRONT` أو `CameraLens.BACK`.
إذا لم يكن في الجهاز العدسة المطلوبة، يستخدم الـSDK أول كاميرا متاحة لديه.
ويُخفى مبدّل الكاميرا أيضاً على الأجهزة التي تحتوي على كاميرا واحدة فقط.
اضبط خيار المبدّل على `false` لتثبيت المستخدم على العدسة الافتراضية لتلك الخطوة.```kotlin theme={null}
val configuration = Configuration(
    defaultLivenessCamera = CameraLens.BACK,
    showLivenessCameraSwitchButton = false
)
```> [!NOTE]
>
> الخيارات `showLanguageSelector` و`showCloseButton` و`showExitConfirmation` و`closeOnComplete` مطابقة لـ`DiditSdkConfiguration` الخاص بـWeb SDK. أما الخياران `languageLocale` و`fontFamily` الخاصان بالأجهزة المحمولة فموجودان لأن الـSDK للأجهزة المحمولة يعرض واجهة التحقق الكاملة بشكل أصلي (على عكس Web SDK الذي يُسند العرض إلى الواجهة المستضافة داخل iframe).> [!NOTE]
>
> **التخصيص والألوان**: تُضبط الألوان والخلفيات وإعدادات شاشة المقدمة من خلال [إعدادات العلامة البيضاء](https://business.didit.me) في Didit Console، وليس في إعدادات الـSDK. يضمن ذلك هوية بصرية متسقة عبر جميع المنصات.***## دعم اللغاتيدعم الـSDK **54 لغة**. وإذا لم تُحدَّد لغة، يستخدم الـSDK لغة الجهاز مع الإنجليزية كبديل احتياطي.```kotlin theme={null}
// Use device locale (default)
val config = Configuration()

// Force specific language
val config = Configuration(languageLocale = SupportedLanguage.FRENCH)

// Let the user change language on the welcome screen
val config = Configuration(showLanguageSelector = true)
```**[عرض جميع اللغات المدعومة ←](https://docs.didit.me/ar/integration/supported-languages.md)*****## الخيارات المتقدمةللمعاملات المتقدمة للجلسة (`contact_details` و`expected_details` و`metadata` و`callback`)، استخدم طريقة **الجلسة من الخادم الخلفي**. يستدعي خادمك الخلفي [واجهة برمجة تطبيقات إنشاء جلسة التحقق](https://docs.didit.me/ar/sessions-api/create-session.md) مع كامل المعاملات، ثم يمرر `session_token` إلى الـSDK.***## معالجة النتائجيوفّر الصنف المغلق (sealed class) `VerificationResult` نتيجة التحقق:### حالات النتيجة| الحالة | الوصف |
| - | - |
| `Completed(session)` | اكتمل مسار التحقق (تحقق من `session.status` للحصول على النتيجة) |
| `Cancelled(session)` | ألغى المستخدم مسار التحقق |
| `Failed(error, session)` | حدث خطأ أثناء التحقق |### خصائص SessionData| الخاصية | النوع | الوصف |
| - | - | - |
| `sessionId` | `String` | معرّف الجلسة الفريد |
| `status` | `VerificationStatus` | `APPROVED` أو `PENDING` أو `DECLINED` |### أنواع الأخطاءجميع الأخطاء أصناف فرعية مغلقة (sealed subclasses) لـ `me.didit.sdk.VerificationError`:| الخطأ | الوصف |
| - | - |
| `SessionExpired` | انتهت صلاحية الجلسة |
| `NetworkError` | مشكلة في الاتصال بالشبكة |
| `CameraAccessDenied` | لم يُمنح إذن الكاميرا |
| `NotInitialized` | لم تتم تهيئة SDK: استدعِ `DiditSdk.initialize(context)` أولاً |
| `ApiError` | أعادت الواجهة الخلفية استجابة خطأ |
| `RetryBlocked` | لا يمكن إعادة المحاولة (مثلاً عند بلوغ الحد الأقصى للمحاولات) |
| `Unknown(message)` | خطأ آخر مع رسالة |### فقدان الاتصالإذا فقد الجهاز اتصاله أثناء التحقق، يعرض SDK شاشة "لا يوجد اتصال بالإنترنت" تغطي مسار التحقق بدلاً من ترك خطوة في حالة التحميل.
يواصل SDK التحقق من الاتصال في الخلفية، ويغلق الشاشة تلقائياً بمجرد عودة إمكانية الوصول إلى Didit، ويتابع المستخدم من الخطوة التي كان عليها.
تعرض الشاشة الزر **حاول مرة أخرى** وعند تعيين `showCloseButton` إلى `true` (القيمة الافتراضية)، الزر **الخروج من التحقق**.
الخروج ينهي التحقق بالنتيجة `VerificationResult.Failed(error = VerificationError.NetworkError, session = ...)`، وبذلك يعرف تطبيقك أن المستخدم خرج بسبب الاتصال.### مثال كامل لمعالجة النتيجة```kotlin theme={null}
DiditSdk.startVerification(token = "your-token") { result ->
    when (result) {
        is VerificationResult.Completed -> {
            when (result.session.status) {
                VerificationStatus.APPROVED -> {
                    Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    // User is verified - grant access
                }
                VerificationStatus.PENDING -> {
                    Log.d("Didit", "Under review. Session: ${result.session.sessionId}")
                    // Show "verification in progress" UI
                }
                VerificationStatus.DECLINED -> {
                    Log.d("Didit", "Declined. Session: ${result.session.sessionId}")
                    // Handle declined verification
                }
            }
        }
        is VerificationResult.Cancelled -> {
            Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            // User chose to cancel - maybe show retry option
        }
        is VerificationResult.Failed -> {
            Log.e("Didit", "Error: ${result.error.message}")
            // Handle error - show retry or contact support
        }
    }
}
```***## مراقبة حالة SDKيمكنك مراقبة حالة SDK لبناء واجهة تحميل مخصصة:```kotlin theme={null}
lifecycleScope.launch {
    DiditSdk.state.collect { state ->
        when (state) {
            is DiditSdkState.Idle -> {
                // Ready to start verification
            }
            is DiditSdkState.CreatingSession -> {
                // Show "Creating session..." progress
            }
            is DiditSdkState.Loading -> {
                // Show loading indicator
            }
            is DiditSdkState.Ready -> {
                // Verification UI is ready - launch it
                DiditSdk.launchVerificationUI(this@MainActivity)
            }
            is DiditSdkState.Error -> {
                // Show error message
                Log.e("Didit", "Error: ${state.message}")
            }
        }
    }
}
```***## ProGuard / R8يتضمن SDK قواعد ProGuard الخاصة بالمستهلك. لا حاجة إلى أي إعداد إضافي.إذا كنت تستخدم وضع R8 الكامل، فقد تحتاج إلى إضافة هذا السطر إلى `gradle.properties`:```properties theme={null}
android.enableR8.fullMode=false
```***## مثال شامل (جلسة الخادم → SDK أندرويد → النتيجة)هذا النمط هو التكامل الجاهز للإنتاج. ينشئ الخادم الخلفي الجلسة، ويستلم تطبيق أندرويد token `session_token`، ويشغّل مسار التحقق عبر SDK.### 1. الخادم الخلفي: إنشاء الجلسة```ts theme={null}
// Node.js / Express example. Run on your server. NEVER ship DIDIT_API_KEY to the device.
import express from "express";

const app = express();
app.use(express.json());

app.post("/api/verification/start", async (req, res) => {
  const response = await fetch("https://verification.didit.me/v3/session/", {
    method: "POST",
    headers: {
      "x-api-key": process.env.DIDIT_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      workflow_id: process.env.DIDIT_WORKFLOW_ID,
      vendor_data: req.body.userId, // your stable user id
    }),
  });

  if (!response.ok) {
    return res.status(500).json({ error: `Didit ${response.status}` });
  }

  const { session_id, session_token } = await response.json();
  // Persist session_id <-> userId so you can match the webhook later.
  res.json({ session_id, session_token });
});
```### 2. أندرويد: تبادل token وتشغيل SDK```kotlin theme={null}
import android.app.Activity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.didit.sdk.DiditSdk
import me.didit.sdk.VerificationResult
import me.didit.sdk.VerificationStatus
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.MediaType.Companion.toMediaType
import org.json.JSONObject

class VerificationFlow(private val activity: ComponentActivity) {
    private val http = OkHttpClient()
    private val json = "application/json".toMediaType()

    fun start(userId: String) {
        activity.lifecycleScope.launch {
            val token = withContext(Dispatchers.IO) {
                val body = JSONObject().put("userId", userId).toString().toRequestBody(json)
                val req = Request.Builder()
                    .url("https://your-backend.example.com/api/verification/start")
                    .post(body)
                    .build()
                http.newCall(req).execute().use { resp ->
                    JSONObject(resp.body!!.string()).getString("session_token")
                }
            }

            DiditSdk.startVerification(token = token) { result ->
                when (result) {
                    is VerificationResult.Completed -> when (result.session.status) {
                        VerificationStatus.APPROVED -> { /* optimistic UI; rely on webhook for source of truth */ }
                        VerificationStatus.PENDING  -> { /* show "under review" */ }
                        VerificationStatus.DECLINED -> { /* show retry/contact support */ }
                    }
                    is VerificationResult.Cancelled -> { /* user cancelled */ }
                    is VerificationResult.Failed    -> { /* show error: result.error.message */ }
                }
            }
        }
    }
}
```### 3. الخادم الخلفي: استلام القرار النهائي عبر webhookنتيجة SDK مفيدة لتقديم ملاحظات في الواجهة، لكن النتيجة المعتمدة تصل عبر webhook. راجع [دليل webhook](https://docs.didit.me/ar/integration/webhooks.md) للتحقق من HMAC.```ts theme={null}
app.post("/api/webhooks/didit", express.raw({ type: "application/json" }), (req, res) => {
  // 1. Verify the X-Signature header (see Webhooks docs)
  // 2. Parse the body
  const event = JSON.parse(req.body.toString());
  if (event.webhook_type === "status.updated") {
    // event.session_id, event.status ("Approved" | "Declined" | "In Review" | ...)
    // Look up the user by session_id and update their verification state.
  }
  res.sendStatus(200);
});
```***## مثال كامل```kotlin theme={null}
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import me.didit.sdk.Configuration
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult
import me.didit.sdk.VerificationStatus
import me.didit.sdk.core.localization.SupportedLanguage

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Idle, Loading, CreatingSession */ }
                }
            }
        }
    }

    fun startVerification() {
        val config = Configuration(
            languageLocale = SupportedLanguage.ENGLISH,
            loggingEnabled = true
        )

        // Method 1: UniLink (no backend required)
        DiditSdk.startVerification(
            workflowId = "your-workflow-id",
            vendorData = "user-123",
            configuration = config
        ) { result ->
            handleResult(result)
        }

        // Method 2: Backend Session (recommended for production)
        // DiditSdk.startVerification(
        //     token = "your-session-token",
        //     configuration = config
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                when (result.session.status) {
                    VerificationStatus.APPROVED -> {
                        Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    }
                    VerificationStatus.PENDING -> {
                        Log.d("Didit", "Under review")
                    }
                    VerificationStatus.DECLINED -> {
                        Log.d("Didit", "Declined")
                    }
                }
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Error: ${result.error.message}")
            }
        }
    }
}
```***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.