> ## 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 التحقق من الهوية لنظام iOS بلغة Swift

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



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



      
      

\<pre>

\`Integrate Didit identity verification into my iOS app using the native Swift SDK (DiditSDK 4.13.2).

\## Requirements
\- iOS 13.0+, Xcode 15.0+, Swift 5.9+
\- NFC chip reading requires iOS 15+ and a compatible device with NFC hardware
\- Since 4.0.0 the SDK ships in four variants; pick exactly one:
\- Core (DiditSDKCore): no NFC, no auto-detection, no OpenSSL, iOS 13.0+, smallest binary (manual capture only)
\- AutoDetection (DiditSDKAutoDetection): ML auto-capture, no NFC, no OpenSSL, iOS 13.0+
\- NFC (DiditSDKNFC): NFC passport reading, bundles OpenSSL 3.3.3, iOS 15.0+
\- All (DiditSDK — default): every feature, bundles OpenSSL 3.3.3, iOS 15.0+

\## Installation

\### Option A: Swift Package Manager (recommended)
1\. In Xcode: File > Add Package Dependencies
2\. Enter URL: https://github.com/didit-protocol/sdk-ios.git
3\. Select version 4.13.2 (or "Up to Next Major") and click Add Package
4\. Add exactly one library product for your variant:
\- All (NFC + auto-detection): product "DiditSDK"
\- Core (no NFC, no auto-detection): product "DiditSDKCore"
\- AutoDetection (auto-capture, no NFC): product "DiditSDKAutoDetection"
\- NFC (NFC, no auto-detection): product "DiditSDKNFC"

In Package.swift:
.package(url: "https://github.com/didit-protocol/sdk-ios.git", from: "4.13.2")
Then add one product, e.g. .product(name: "DiditSDK", package: "DiditSDK") or .product(name: "DiditSDKCore", package: "DiditSDK"). Your code always writes import DiditSDK regardless of variant.

\### Option B: CocoaPods (binary podspec — DiditSDK is not on the public Trunk)
podspec_url = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.13.2/DiditSDK.podspec'
\# Pick exactly one subspec:
\# All (NFC + auto-detection, iOS 15+):
platform :ios, '15.0'
pod 'DiditSDK/All', :podspec => podspec_url
\# Core (no NFC, no auto-detection, iOS 13+):        pod 'DiditSDK/Core', :podspec => podspec_url
\# AutoDetection (auto-capture, no NFC, iOS 13+):    pod 'DiditSDK/AutoDetection', :podspec => podspec_url
\# NFC (NFC, no auto-detection, iOS 15+):            pod 'DiditSDK/NFC', :podspec => podspec_url

Then run: pod install
Open the .xcworkspace (not .xcodeproj).

On Xcode 15+ if you hit rsync "Operation not permitted", set Build Setting ENABLE_USER_SCRIPT_SANDBOXING to No on the project (Debug and Release).

\## Required Permissions (Info.plist)
\- NSCameraUsageDescription (required) — Document scanning and face verification
\- NSMicrophoneUsageDescription (required) — Video recording for liveness checks
\- NSPhotoLibraryUsageDescription (required) — Upload documents from gallery
\- NFCReaderUsageDescription (only if using the NFC or All variant) — Read NFC chips in passports/IDs
\- NSLocationWhenInUseUsageDescription (optional) — Geolocation for fraud prevention

\## NFC Configuration (NFC or All variant only — skip for the Core or AutoDetection variants)
1\. Add "Near Field Communication Tag Reading" capability in Xcode > Signing & Capabilities
2\. Add ISO7816 identifiers to Info.plist:
com.apple.developer.nfc.readersession.iso7816.select-identifiers:
\["D23300000045737445494420763335", "A0000002471001", "A0000002472001", "00000000000000", "D392F000260100000001"]
(D392F000260100000001 is the Japan My Number Card's JPKI application: without it, iOS does not report that card to the SDK.)
3\. Add to entitlements file:
com.apple.developer.nfc.readersession.formats: ["TAG"]

\## 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 iOS app (never expose DIDIT_API_KEY to the device).

\## SwiftUI Integration (recommended)
import SwiftUI
import DiditSDK

struct ContentView: View {
var body: some View {
    Button("Verify Identity") {
        // Option A: With session token from your backend (recommended)
        DiditSdk.shared.startVerification(token: "session-token-from-backend")

        // Option B: With workflow ID (SDK creates session internally — UniLink, vendorData only)
        // DiditSdk.shared.startVerification(workflowId: "your-workflow-id", vendorData: "user-id")
    }
    .diditVerification { result in
        switch result {
        case .completed(let session):
            // session.status: VerificationStatus = .approved | .pending | .declined
            if session.status == .approved { /* grant access */ }
        case .cancelled(let session):
            // User dismissed the flow; session may be nil if none was created
            \_ = session
        case .failed(let error, _):
            // VerificationError — show error.localizedDescription
            \_ = error
        }
    }
}
}

\## Programmatically dismissing the verification (3.6.0+)
Call DiditSdk.shared.dismiss() to end an active verification (e.g. on app backgrounding).
It dismisses the UI, resets state, and fires the .diditVerification handler with .cancelled(session:).
Do NOT toggle DiditSdk.shared.isPresented = false or call UIKit dismiss() on the topmost VC — that bypasses the completion pipeline.

\## Result Statuses (SDK enum / API string)
\- .approved / "Approved"  — user identity verified, grant access
\- .declined / "Declined"  — verification failed, show retry or contact support
\- .pending  / "In Review" — 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 iOS app)
\- DIDIT_API_KEY — from Didit Console > API & Webhooks
\- DIDIT_WORKFLOW_ID — from Didit Console > Workflows

\## App Store Note
If you ship the NFC or All variant, Apple may request an NFC demo video during review. Request ours from [support@didit.me](mailto:support@didit.me).

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

\</pre>



      
      

الصق في

SDK خفيف الوزن يعتمد على الخادم لتنفيذ التحقق من الهوية، ويتطلب الحد الأدنى من الإعدادات. **أحدث إصدار: 4.13.2.**> [card] [مستودع GitHub](https://github.com/didit-protocol/sdk-ios)
>
> اطّلع على الشيفرة المصدرية والإصدارات وسجل التغييرات الكامل على GitHub> [!NOTE]
>
> ### **حزمة SDK الأصلية**: هذا هو الأسلوب الموصى به لتطبيقات iOS. توفر حزمة SDK الأصلية أفضل تجربة للمستخدم، ومعالجة محسّنة للكاميرا، ودعمًا كاملًا لتقنية NFC.***## المتطلبات| المتطلب | الحد الأدنى للإصدار |
| - | - |
| iOS | 13.0+ |
| Xcode | 15.0+ |
| Swift | 5.9+ |### توافق إصدارات iOS| إصدار iOS | الميزات المتاحة |
| - | - |
| iOS 13.0 - 14.x | جميع الميزات **باستثناء** قراءة جواز السفر عبر NFC |
| iOS 15.0+ | جميع الميزات، بما فيها قراءة جواز السفر عبر NFC |> [!NOTE]
>
> **تتطلب الموافقة البيومترية حزمة SDK الأصلية 4.10.0 أو أحدث.** بالنسبة للأشخاص المشمولين بقوانين Illinois وTexas وColorado، يمكن لـ Didit أن تطلب [الموافقة البيومترية الصريحة](https://docs.didit.me/ar/getting-started/biometric-consent.md) قبل أول التقاط للوجه. تعرض إصدارات iOS SDK 4.10.0 وما بعدها هذه الخطوة. ولا تستطيع الإصدارات السابقة عرض هذه الخطوة: تعمل جلساتها كما كانت من قبل، ويُبلغ القرار بأن الموافقة لم تُجمع (`biometric_consent.reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK"`). قم بالترقية إذا كنت تتحقق من هوية أشخاص في تلك الولايات.***## التثبيتمنذ الإصدار `4.0.0` يُوزَّع SDK في عدة متغيرات قابلة للتثبيت، حتى لا يتحمل تطبيقك حجم الملف الثنائي إلا للميزات التي يستخدمها. اختر متغيراً واحداً بالضبط: subspec واحداً في CocoaPods ومنتج مكتبة واحداً في SwiftPM.| المتغير | CocoaPods | منتج SwiftPM | NFC | الكشف التلقائي | OpenSSL | أدنى إصدار iOS |
| - | - | - | :-: | :-: | - | - |
| **Core** | `DiditSDK/Core` | `DiditSDKCore` | – | ✓ | لا يوجد | iOS 13.0+ |
| **AutoDetection** (مهجور) | `DiditSDK/AutoDetection` | `DiditSDKAutoDetection` | – | ✓ | لا يوجد | iOS 13.0+ |
| **NFC** | `DiditSDK/NFC` | `DiditSDKNFC` | ✓ | ✓ | `3.3.3` مضمّن | iOS 15.0+ |
| **الكل** (الافتراضي) | `DiditSDK/All` | `DiditSDK` | ✓ | ✓ | `3.3.3` مضمّن | iOS 15.0+ |- **Core**: الأخفّ حجماً، مع التقاط تلقائي للمستند وصورة السيلفي عبر أدوات الكشف الخفيفة الخاصة بـDidit. لا يتضمن `OpenSSL.xcframework` ولا بيئة تشغيل CoreNFC.
- **AutoDetection**: مهجور منذ الإصدار 4.11.0 وهو مطابق لـ**Core**؛ استخدم **Core** بدلاً منه.
- **NFC**: **Core** مع قراءة شريحة جواز السفر أو الهوية الإلكترونية عبر NFC.
- **الكل**: كل الميزات. وهذا هو الافتراضي عند تثبيت `DiditSDK` دون تسمية subspec أو منتج.ما يضيفه كل متغير إلى حزمة تطبيقك (arm64 Mach-O، مقاساً على الإصدار `4.9.0`): **Core** \~11.1 MB، **NFC** \~11.7 MB بالإضافة إلى \~4 MB من OpenSSL، **AutoDetection** \~16.0 MB، **الكل** \~16.6 MB بالإضافة إلى OpenSSL.
تُنزَّل نماذج الكشف نفسها أثناء التشغيل وتُخزَّن مؤقتاً، لذلك لا تُحتسب أبداً ضمن حجم تنزيل تطبيقك.منذ الإصدار `4.11.0` يعمل الالتقاط التلقائي على أدوات الكشف الخفيفة الخاصة بـDidit في كل المتغيرات. لم يعد TensorFlow Lite جزءاً من SDK، وأصبح الإطار أصغر لأن ترجماته تُحمَّل من خارج الملف الثنائي.منذ الإصدار `4.6.0` لم تعد الأطر المُرسَلة تحتوي على واصفات Swift ABI (بيانات وصفية للبناء كان Xcode ينسخها إلى كل تطبيق دون أن يقرأها) ولا على فيديوهات تعليمية لا يستطيع المتغير تشغيلها. الترقية من `4.5.4` أو إصدار أقدم تقلّص حجم تطبيقك بنحو 7-8 MB وحدها، دون أي تغيير في الكود.
يضغط App Store الملفات الثنائية عند التسليم، لذلك يكون حجم التنزيل عبر الهواء أقل. راجع تقرير حجم التطبيق في App Store Connect للحصول على الفرق الدقيق لكل جهاز.> [!NOTE]
>
> يحتوي المتغيران **NFC** و**الكل** على `OpenSSL.xcframework` (**OpenSSL 3.3.3**، ويُوزَّع باسم `OpenSSL-Universal 3.3.3001` عبر `NFCPassportReader`)، وهو مطلوب للمصادقة على شريحة NFC ويحتاج إلى iOS 15.0+. الإصدارات حتى 4.0.6، بما فيها 4.0.6، كانت تحزم OpenSSL `1.1.1s`؛ أما **4.0.7 وما بعده** فتأتي مع OpenSSL 3.3.3 وله بيان خصوصية وتوقيع كود خاصان به، لذا ثبّت دائماً **4.0.7 أو أحدث**. تجدر الإشارة إلى أن الترقية تُوحّد *إصدارات* OpenSSL لكنها لا تزيل تعارضات *التضمين*: إذا ضمّن اعتماد آخر في تطبيقك أيضاً `OpenSSL.framework` (بنفس اسم الملف ونفس معرّف الحزمة `com.github.krzyzanowskim.OpenSSL`)، فستتعارض النسختان عند خطوة التضمين بغض النظر عن الإصدار. احتفظ بنسخة واحدة فقط، مثلاً بتجاوز الحزمة الأخرى بواسطة هوية SPM لاستخدام `OpenSSL.xcframework` المنشور من Didit، حتى يكون الملف الثنائي في الحزمة هو الذي بُني عليه هذا SDK. أما متغيرا **Core** و**AutoDetection** فلا يربطان OpenSSL إطلاقاً.تبقى `import DiditSDK` كما هي في كود تطبيقك بغض النظر عن المتغير الذي تثبّته.### Swift Package Manager (موصى به)أضف الحزمة إلى مشروعك عبر Xcode:1) انتقل إلى **File > Add Package Dependencies**
2) أدخل عنوان URL للمستودع:```
https://github.com/didit-protocol/sdk-ios.git
```3) اختر الإصدار (أو **Up to Next Major** بدءاً من `4.13.2`) ثم انقر **Add Package**
4) عند ظهور سؤال اختيار المنتج، اختر منتج مكتبة واحداً بالضبط لمتغيرك (راجع الجدول أعلاه)أو في ملف `Package.swift` الخاص بك:```swift theme={null}
dependencies: [
    .package(url: "https://github.com/didit-protocol/sdk-ios.git", from: "4.13.2")
]
```ثم أضف منتجاً واحداً بالضبط من هذه المنتجات إلى الهدف (target) في مشروعك:```swift theme={null}
// All (default — NFC + auto-detection)
.product(name: "DiditSDK", package: "DiditSDK")

// Core (no NFC, no auto-detection, no OpenSSL)
.product(name: "DiditSDKCore", package: "DiditSDK")

// AutoDetection (auto-capture, no NFC)
.product(name: "DiditSDKAutoDetection", package: "DiditSDK")

// NFC (NFC passport reading, no auto-detection)
.product(name: "DiditSDKNFC", package: "DiditSDK")
```> [!WARNING]
>
> **لا يفرض Swift Package Manager حد iOS 15 عليك.** يعلن `Package.swift` عن `platforms: [.iOS(.v13)]` للحزمة كلها، لذا سيسمح لك Xcode بإضافة `DiditSDK` أو `DiditSDKNFC` إلى هدف يعمل بـiOS 13 أو 14 دون أي اعتراض، مع أن الاثنين يحزمان `OpenSSL.xcframework` ويقرآن الشرائح عبر `NFCPassportReader`، وهما يحتاجان إلى **iOS 15.0+**. اضبط هدف النشر لهدفك على 15.0 بنفسك عند استخدام منتج `All` أو `NFC`. أما CocoaPods فيفرض ذلك تلقائياً عبر `deployment_target` الخاص بالـsubspec.### CocoaPodsيُوزَّع `DiditSDK` كـpodspec ثنائي مستضاف في المستودع (وليس على CocoaPods Trunk العام)، لذا يجب أن تشير إلى رابط الـpodspec. اختر subspec واحداً بالضبط:```ruby theme={null}
podspec_url = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/4.13.2/DiditSDK.podspec'

# All (NFC + auto-detection, iOS 15.0+):
platform :ios, '15.0'
pod 'DiditSDK/All', :podspec => podspec_url

# Core (no NFC, no auto-detection, iOS 13.0+):
# pod 'DiditSDK/Core', :podspec => podspec_url

# AutoDetection (auto-capture, no NFC, iOS 13.0+):
# pod 'DiditSDK/AutoDetection', :podspec => podspec_url

# NFC (NFC passport reading, iOS 15.0+):
# pod 'DiditSDK/NFC', :podspec => podspec_url
```يدعم `Core` و`AutoDetection` iOS 13 كحد أدنى، أما `NFC` و`All` فيحتاجان إلى iOS 15 بسبب `NFCPassportReader`.ثم شغّل:```bash theme={null}
pod install
```> [!NOTE]
>
> بعد `pod install`، افتح ملف `.xcworkspace` المُنشأ (وليس `.xcodeproj`).> [!NOTE]
>
> **أخطاء rsync في Xcode 15+**: إذا ظهرت أخطاء rsync من نوع `Operation not permitted` أثناء البناء، فاضبط **Build Settings → User Script Sandboxing** (`ENABLE_USER_SCRIPT_SANDBOXING`) على **No** في المشروع لكل من Debug وRelease.### التثبيت اليدوي (XCFramework)ينشر كل إصدار إطار XCFramework واحداً لكل متغير. نزّل ملفات zip لمتغيرك من صفحة [GitHub Releases](https://github.com/didit-protocol/sdk-ios/releases)، ثم اسحب مجلدات `.xcframework` إلى Xcode واضبط **Embed & Sign**.| المتغير | التنزيل |
| - | - |
| **Core** | `DiditSDK-Core.xcframework.zip` |
| **AutoDetection** | `DiditSDK-AutoDetection.xcframework.zip` |
| **NFC** | `DiditSDK-NFC.xcframework.zip` + `OpenSSL.xcframework.zip` |
| **الكل** | `DiditSDK.xcframework.zip` + `OpenSSL.xcframework.zip` |***## الأذوناتيتطلب SDK الأذونات التالية. أضفها إلى ملف `Info.plist` الخاص بتطبيقك:| الإذن | مفتاح Info.plist | الوصف | مطلوب |
| - | - | - | - |
| الكاميرا | `NSCameraUsageDescription` | مسح المستندات والتحقق من الوجه | ✅ نعم |
| الميكروفون | `NSMicrophoneUsageDescription` | تسجيل الفيديو لفحوصات الحيوية | ✅ نعم |
| مكتبة الصور | `NSPhotoLibraryUsageDescription` | رفع المستندات من معرض الجهاز | ✅ نعم |
| NFC | `NFCReaderUsageDescription` | قراءة شرائح NFC في جوازات السفر وبطاقات الهوية | ⚠️ للحزمة الكاملة فقط |
| الموقع | `NSLocationWhenInUseUsageDescription` | تحديد الموقع الجغرافي لمنع الاحتيال | ❌ اختياري |### أمثلة على إدخالات Info.plist```xml theme={null}
<key>NSCameraUsageDescription</key>
<string>Camera access is required to scan your identity documents for verification.</string>

<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required to record video for liveness verification.</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is required to upload document images.</string>

<key>NFCReaderUsageDescription</key>
<string>NFC access is required to read the chip in your identity document.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access helps verify your identity and prevent fraud.</string>
```### إعداد NFCمطلوب فقط عند تثبيت نسخة **NFC** أو **الكل**. تخطَّ هذا القسم إذا ثبّتَّ نسخة **Core** أو **AutoDetection**.لتفعيل قراءة NFC لجوازات السفر وبطاقات الهوية المزودة بشرائح:1) **أضف إمكانية NFC** في Xcode:
   * اختر الهدف (Target) الخاص بك ← **Signing & Capabilities** ← **+ Capability** ← **Near Field Communication Tag Reading**

2) **أضف معرّفات ISO7816** إلى `Info.plist`:```xml theme={null}
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
    <string>D23300000045737445494420763335</string>
    <string>A0000002471001</string>
    <string>A0000002472001</string>
    <string>00000000000000</string>
    <string>D392F000260100000001</string>
</array>
```يتيح المعرّف `D392F000260100000001` للـ SDK قراءة بطاقة My Number اليابانية عبر [JPKI](https://docs.didit.me/ar/core-technology/nfc-verification/overview.md#بطاقة-ماي-نمبر-اليابانية-jpki)، فمن دونه لا يُبلغ iOS الـ SDK بوجود البطاقة. قراءة بطاقة My Number غير مفعّلة في بيئة الإنتاج بعد، ولا يغيّر المعرّف شيئاً بالنسبة إلى المستندات الأخرى، لذا يمكنك إضافته الآن.3) **أضف الاستحقاقات** (في ملف `.entitlements` الخاص بك):```xml theme={null}
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>TAG</string>
</array>
```> [!WARNING]
>
> **قيد المحاكي (نسخ NFC والكل)**: تربط هذه النسخ مكتبة CoreNFC، ومنذ Xcode 12 لم يعد الملف `libnfshared.dylib` موجوداً في المحاكيات. راجع [هذا الموضوع على Stack Overflow](https://stackoverflow.com/questions/63915728/xcode12-corenfc-simulator-library-not-loaded) للاطلاع على حل بديل. هذا **لا** ينطبق على نسخة **Core** أو **AutoDetection**. اختبر ميزات NFC على الأجهزة الفعلية فقط.> [!NOTE]
>
> ### **مراجعة App Store (نسخ NFC والكل)**: إذا ثبّتَّ نسخة **NFC** أو **الكل**، فقد يطلب Apple فيديو توضيحياً أثناء المراجعة، لأن الشيفرة المرتبطة بـ NFC جزء من ملف الـ SDK الثنائي، حتى لو لم يستخدم سير العمل الخاص بك NFC. اطلب فيديو العرض التوضيحي لـ NFC لإرساله إلى Apple من [support@didit.me](mailto:support@didit.me). هذا لا ينطبق على نسخة **Core** أو **AutoDetection**.***## البدء السريع### تكامل SwiftUI```swift theme={null}
import SwiftUI
import DiditSDK

struct ContentView: View {
    var body: some View {
        Button("Verify Identity") {
            // Method 1: UniLink — no backend required
            DiditSdk.shared.startVerification(workflowId: "your-workflow-id")
            
            // Method 2: Backend Session — full parameter control
            // DiditSdk.shared.startVerification(token: "your-session-token")
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            print("Completed: \(session.status)")
        case .cancelled(let session):
            print("Cancelled")
        case .failed(let error, _):
            print("Failed: \(error.localizedDescription)")
        }
    }
}
```### تكامل UIKit```swift theme={null}
import UIKit
import DiditSDK

class VerificationViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Start verification when ready
        DiditSdk.shared.startVerification(token: "your-session-token")
    }
}
```***## طرق التكامليدعم SDK طريقتين للتكامل:### الطريقة 1: UniLink (الأبسط)لا يتطلب خادماً خلفياً. يُنشئ SDK الجلسة مباشرة باستخدام معرّف سير العمل الخاص بك من [Didit Console](https://business.didit.me). تدعم طريقة UniLink (`startVerification(workflowId:)`) الحقل `vendorData` فقط، ولأي معامل آخر للجلسة استخدم الطريقة 2.> [!NOTE]
>
> لكي يُرفق `vendorData` بالجلسة عبر UniLink، فعّل خيار **بيانات البائع** في [Didit Console](https://business.didit.me).```swift theme={null}
DiditSdk.shared.startVerification(
    workflowId: "your-workflow-id",
    vendorData: "user-123"
)
```### الطريقة 2: جلسة من الخادم الخلفي (موصى بها للإنتاج)ينشئ خادمك الخلفي الجلسة عبر [واجهة إنشاء جلسة التحقق (Create Verification Session API)](https://docs.didit.me/ar/sessions-api/create-session.md) (`POST /v3/session/`) مع دعم كامل للمعاملات (`contact_details`, `expected_details`, `metadata`, `callback`، وغيرها)، ثم يمرر `session_token` إلى SDK.```swift theme={null}
// Your backend creates a session and returns the token
let sessionToken = await yourBackend.createVerificationSession(userId: currentUser.id)

// Pass the token to the SDK
DiditSdk.shared.startVerification(token: sessionToken)
```تمنحك هذه الطريقة تحكماً كاملاً في:- ربط الجلسات بمستخدميك (`vendor_data`)
- تحديد بيانات الاتصال والبيانات المتوقعة للتحقق المتبادل
- تعيين بيانات وصفية مخصصة
- ضبط روابط الاستدعاء لكل جلسة
  تُرسل هذه البيانات (بيانات الاتصال، والبيانات المتوقعة، والبيانات الوصفية، ورابط الاستدعاء) إلى [واجهة إنشاء جلسة التحقق](https://docs.didit.me/ar/sessions-api/create-session.md).***## الإعداداتخصِّص سلوك SDK باستخدام `DiditSdk.Configuration`:```swift theme={null}
let configuration = DiditSdk.Configuration(
    languageLocale: .spanish,      // Force Spanish language
    showLanguageSelector: true,    // Let the user change language
    fontFamily: "Avenir",          // Custom font (must be registered in your app)
    loggingEnabled: true,          // Enable debug logging
    showCloseButton: true,         // Show close (X) button on step screens
    showExitConfirmation: true,    // Show confirmation dialog when user taps close
    closeOnComplete: false         // Don't auto-dismiss on completion
)

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

// Force specific language
let config = DiditSdk.Configuration(languageLocale: .french)

// Let the user change language on the welcome screen
let config = DiditSdk.Configuration(showLanguageSelector: true)

// Detect device locale programmatically
let deviceLanguage = SupportedLanguage.fromDeviceLocale()
```**[عرض جميع اللغات المدعومة ←](https://docs.didit.me/ar/integration/supported-languages.md)*****## معلمات الجلسة المتقدمةلاستخدام معلمات الجلسة المتقدمة (`contact_details` و`expected_details` و`metadata` و`callback`)، استخدم طريقة **Backend Session**. يستدعي الخادم الخلفي لديك [واجهة برمجة تطبيقات إنشاء جلسة التحقق](https://docs.didit.me/ar/sessions-api/create-session.md) بالمعلمات الكاملة، ثم يمرر `session_token` إلى SDK.***## معالجة النتائجيوفر التعداد `VerificationResult` نتيجة التحقق:### حالات النتيجة| الحالة | الوصف |
| - | - |
| `.completed(session:)` | اكتمل مسار التحقق (راجع `session.status` للنتيجة) |
| `.cancelled(session:)` | ألغى المستخدم مسار التحقق |
| `.failed(error:session:)` | حدث خطأ أثناء التحقق |### خصائص SessionData| الخاصية | النوع | الوصف |
| - | - | - |
| `sessionId` | `String` | معرّف الجلسة الفريد |
| `status` | `VerificationStatus` | `.approved` أو `.pending` أو `.declined` |
| `country` | `String?` | رمز الدولة (ISO 3166-1 alpha-3) |
| `documentType` | `String?` | نوع المستند المستخدم للتحقق |### أنواع الأخطاء| الخطأ | الوصف |
| - | - |
| `.sessionExpired` | انتهت صلاحية الجلسة |
| `.networkError` | مشكلة في الاتصال بالشبكة |
| `.cameraAccessDenied` | لم يُمنح إذن الكاميرا |
| `.unknown(String)` | خطأ آخر مع رسالة |### فقدان الاتصالإذا فقد الجهاز اتصاله أثناء التحقق، يعرض SDK شاشة "لا يوجد اتصال بالإنترنت" بدلاً من ترك الخطوة قيد التحميل.
يواصل SDK التحقق من الاتصال في الخلفية، ويغلق الشاشة تلقائياً بمجرد إمكانية الوصول إلى Didit مرة أخرى، فيكمل المستخدم من الخطوة التي كان عليها.
تعرض الشاشة الزر **حاول مرة أخرى** و، عندما تكون قيمة `showCloseButton` هي `true` (القيمة الافتراضية)، الزر **الخروج من التحقق**.
الخروج ينهي التحقق بالنتيجة `.failed(error: .networkError, session:)`، فيعرف تطبيقك أن المستخدم خرج بسبب الاتصال.### مثال كامل لمعالجة النتائج```swift theme={null}
.diditVerification { result in
    switch result {
    case .completed(let session):
        switch session.status {
        case .approved:
            print("✅ Approved! Session: \(session.sessionId)")
            // User is verified - grant access
            
        case .pending:
            print("⏳ Under review. Session: \(session.sessionId)")
            // Show "verification in progress" UI
            
        case .declined:
            print("❌ Declined. Session: \(session.sessionId)")
            // Handle declined verification
        }
        
    case .cancelled(let session):
        if let session = session {
            print("🚫 Cancelled session: \(session.sessionId)")
        }
        // User chose to cancel - maybe show retry option
        
    case .failed(let error, let session):
        print("⚠️ Error: \(error.localizedDescription)")
        // Handle error - show retry or contact support
    }
}
```***## إغلاق التحقق برمجياً> [!NOTE]
>
> متاح في DiditSDK ابتداءً من الإصدار **3.6.0+**.يمكن للتطبيق المضيف إنهاء التحقق النشط برمجياً باستخدام `DiditSdk.shared.dismiss()`. وهذه هي الطريقة الموصى بها لإنهاء التحقق عندما يحتاج التطبيق المضيف إلى تولّي التحكم في الشاشة، على سبيل المثال عندما ينتقل التطبيق إلى الخلفية.```swift theme={null}
DiditSdk.shared.dismiss()
```يمرّ `dismiss()` عبر مسار الإكمال المعتاد في SDK: يُغلق الواجهة المعروضة، ويُعيد ضبط الحالة الداخلية، ويستدعي المعالج `.diditVerification` مع `.cancelled(session:)` الذي يحمل `sessionId` الحالي إذا كانت جلسة قد أُنشئت. ولا يكون لاستدعائه أي أثر عندما لا يكون هناك تحقق نشط.### مثال: الإغلاق عند انتقال التطبيق إلى الخلفية```swift theme={null}
NotificationCenter.default.addObserver(
    forName: UIApplication.didEnterBackgroundNotification,
    object: nil,
    queue: .main
) { _ in
    DiditSdk.shared.dismiss()
}
```> [!WARNING]
>
> لا **تُعيّن** `DiditSdk.shared.isPresented = false` للإغلاق، فهذا العلَم يُفعِّل العرض عند حافته الصاعدة فقط، وتعيينه إلى `false` لا يُحدث أي أثر. وبالمثل، فإن استدعاء `dismiss(animated:)` من UIKit على أعلى متحكم عرض غير مدعوم، إذ يتجاوز مسار الإكمال في SDK، فلا يُستدعى المعالج `.diditVerification` أبداً.***## مراقبة حالة SDKيمكنك مراقبة حالة SDK لبناء واجهة تحميل مخصصة:```swift theme={null}
struct CustomView: View {
    @ObservedObject private var sdk = DiditSdk.shared
    
    var body: some View {
        VStack {
            switch sdk.state {
            case .idle:
                Text("Ready to verify")
            case .creatingSession:
                ProgressView("Creating session...")
            case .loading:
                ProgressView("Loading...")
            case .ready:
                Text("Verification in progress")
            case .error(let message):
                Text("Error: \(message)")
            }
        }
    }
}
```***## مثال شامل (من جلسة الخادم الخلفي إلى SDK لنظام iOS إلى النتيجة)هذا النمط هو التكامل الجاهز للإنتاج. يُنشئ الخادم الخلفي الجلسة، ويستلم تطبيق iOS الخاص بك `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. iOS: تبادل الرمز وبدء SDK```swift theme={null}
import SwiftUI
import DiditSDK

struct VerifyButton: View {
    let userId: String
    @State private var error: String?

    var body: some View {
        Button("Verify Identity") {
            Task { await start() }
        }
        .diditVerification { result in
            switch result {
            case .completed(let session) where session.status == .approved:
                // Optimistically reflect success in the UI; rely on the webhook
                // delivered to your backend as the source of truth.
                break
            case .completed(let session):
                print("Terminal status: \(session.status.rawValue)")
            case .cancelled:
                print("User cancelled")
            case .failed(let err, _):
                error = err.localizedDescription
            }
        }
    }

    private func start() async {
        do {
            var req = URLRequest(url: URL(string: "https://your-backend.example.com/api/verification/start")!)
            req.httpMethod = "POST"
            req.setValue("application/json", forHTTPHeaderField: "Content-Type")
            req.httpBody = try JSONEncoder().encode(["userId": userId])

            let (data, _) = try await URLSession.shared.data(for: req)
            struct Payload: Decodable { let session_token: String }
            let payload = try JSONDecoder().decode(Payload.self, from: data)

            await MainActor.run {
                DiditSdk.shared.startVerification(token: payload.session_token)
            }
        } catch {
            self.error = error.localizedDescription
        }
    }
}
```### 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);
});
```***## مثال SwiftUI كامل```swift theme={null}
import SwiftUI
import DiditSDK

struct HomeView: View {
    @State private var resultMessage: String?
    @State private var isVerified = false
    
    var body: some View {
        VStack(spacing: 24) {
            if isVerified {
                Image(systemName: "checkmark.circle.fill")
                    .font(.system(size: 64))
                    .foregroundColor(.green)
                Text("Identity Verified")
                    .font(.title2)
            } else {
                Button("Verify Identity") {
                    startVerification()
                }
                .font(.headline)
                .padding(.horizontal, 32)
                .padding(.vertical, 16)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(12)
            }
            
            if let message = resultMessage {
                Text(message)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                    .padding()
            }
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func startVerification() {
        let config = DiditSdk.Configuration(
            languageLocale: .english
        )
        
        // Method 1: UniLink — no backend required
        DiditSdk.shared.startVerification(
            workflowId: "your-workflow-id",
            vendorData: "user-123",
            configuration: config
        )
        
        // Method 2: Backend Session — full parameter control
        // DiditSdk.shared.startVerification(
        //     token: "your-session-token",
        //     configuration: config
        // )
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            if session.status == .approved {
                isVerified = true
            }
            resultMessage = """
                Status: \(session.status.rawValue)
                Session: \(session.sessionId)
                Country: \(session.country ?? "N/A")
                Document: \(session.documentType ?? "N/A")
                """
                
        case .cancelled(let session):
            resultMessage = "Cancelled - Session: \(session?.sessionId ?? "unknown")"
            
        case .failed(let error, _):
            resultMessage = "Failed: \(error.localizedDescription)"
        }
    }
}
```***


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