Skip to main content

Documentation Index

Fetch the complete documentation index at: https://jdev-e8db0569.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

iOS

Requirements

  • Minimum iOS version: iOS 13.0 or higher
  • CocoaPods: Required for dependency management
  • Swift: The native implementation is written in Swift

Dependencies

The library depends on the native SEON Orchestration SDK, declared in the podspec:
s.dependency 'SEONOrchSDK'

UINavigationController Handling

The SEON SDK requires a UINavigationController to present its verification UI. The library handles this automatically:
  1. Retrieves the root view controller from the key window
  2. If it’s already a UINavigationController, uses it directly
  3. If not, wraps the verification flow in a new UINavigationController
  4. Presents the navigation controller modally
guard let rootViewController = self.findRootViewController() else {
    flutterResult(FlutterError(code: "E_VERIFICATION_FAILED", message: "Unable to find root view controller.", details: nil))
    return
}

self.pendingResult = flutterResult

let navigationController: UINavigationController
if let navController = rootViewController as? UINavigationController {
    navigationController = navController
} else if let navController = rootViewController.navigationController {
    navigationController = navController
} else {
    let placeholderVC = UIViewController()
    placeholderVC.view.backgroundColor = .clear
    let navController = UINavigationController(rootViewController: placeholderVC)
    navController.setNavigationBarHidden(true, animated: false)
    navController.modalPresentationStyle = .fullScreen
    self.presentedNavigationController = navController
    rootViewController.present(navController, animated: false) {
        SEONOrchSDKService.shared.delegate = self
        SEONOrchSDKService.shared.startWebIdVerificationFlow(navigationController: navController)
    }
    return
}

SEONOrchSDKService.shared.delegate = self
SEONOrchSDKService.shared.startWebIdVerificationFlow(navigationController: navigationController)

State Management

Both iOS and Android maintain the initialized state across multiple verification flows. The SDK remains initialized after startVerification() completes. To explicitly reset the state and release resources, call dispose().

Thread Safety

All SDK operations are dispatched to the main thread:
DispatchQueue.main.async {
    // All SDK calls happen here
}
This is critical because:
  • Flutter MethodChannel calls may arrive on any thread
  • UIKit operations must run on the main thread
  • SDK delegate callbacks need main thread context

Permissions

Required Info.plist keys:
Permission KeyPurpose
NSCameraUsageDescriptionID verification and selfie capture
NSMicrophoneUsageDescriptionVideo liveness checks
NSLocationWhenInUseUsageDescriptionGeoLocation for fraud prevention API
NSPhotoLibraryUsageDescriptionProof of address document upload
<key>NSCameraUsageDescription</key>
<string>Required for ID verification and selfie capture</string>

<key>NSMicrophoneUsageDescription</key>
<string>Required for video liveness checks</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Required for fraud prevention</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>Required for proof of address document upload</string>
The SEON SDK handles runtime permission requests automatically during the verification flow.

Android

Requirements

  • Minimum SDK version: API 26 (Android 8.0) or higher
  • Compile SDK version: API 36 (as configured in the plugin’s build.gradle)
  • Kotlin: The library is written in Kotlin

Dependencies

The library depends on the native SEON Orchestration SDK from Maven Central:
dependencies {
    implementation 'io.seon:orchestration-android-sdk:0.1.0'
}
Ensure your project includes mavenCentral() in repositories:
allprojects {
    repositories {
        mavenCentral()
    }
}

Proxy Activity Pattern

The Android implementation uses a transparent proxy Activity to manage the verification flow. Why a proxy Activity:
  1. Lifecycle requirementActivityResultLauncher must be registered before the STARTED lifecycle state
  2. Clean separation — Keeps verification logic separate from the host app’s Activities
  3. Result management — Provides a clean way to bridge async results back to Dart
  4. No UI interference — Transparent theme means users don’t see the proxy Activity
Manifest configuration:
<activity
    android:name=".SeonVerificationActivity"
    android:theme="@android:style/Theme.Translucent.NoTitleBar"
    android:exported="false" />
AttributePurpose
Theme.Translucent.NoTitleBarMakes the Activity invisible to users
exported="false"Activity is only for internal use

MissingLocationPermission Status

Android has a specific verification status for missing location permissions. The proxy Activity maps SEONOrchFlowResult result codes to status strings:
val resultMap = HashMap<String, Any?>()

when (resultCode) {
    SEONOrchFlowResult.Completed.code -> {
        resultMap["status"] = "completed"
    }
    SEONOrchFlowResult.CompletedSuccess.code -> {
        resultMap["status"] = "completedSuccess"
    }
    SEONOrchFlowResult.Error.code -> {
        resultMap["status"] = "error"
        val errorMessage = data?.getStringExtra(VERIFICATION_ERROR_KEY)
        if (errorMessage != null) {
            resultMap["errorMessage"] = errorMessage
        }
    }
    // ... other result codes mapped similarly
}
The missingLocationPermission value exists in the Dart enum for forward compatibility but is not currently emitted by the native Android SDK. Location permission denial is reported as an error status with a descriptive errorMessage.

Permissions

Required permissions in AndroidManifest.xml:
<!-- Always required -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

<!-- Optional: only if your workflow uses geolocation-based fraud detection -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Only for older Android versions -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                 android:maxSdkVersion="32" />

Hardware Feature Declarations

You should also declare required hardware features. These affect Google Play Store filtering — devices without a camera will not see your app in the store:
<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
PermissionPurpose
CAMERAID verification and selfie capture
RECORD_AUDIO / MODIFY_AUDIO_SETTINGSVideo liveness checks
ACCESS_FINE_LOCATIONGeoLocation for fraud prevention API
WRITE_EXTERNAL_STORAGE / READ_EXTERNAL_STORAGEProof of address document handling (legacy Android)
The SEON SDK handles runtime permission requests during the verification flow. If permissions are denied, the verification will fail with an appropriate status.

ActivityResultLauncher Lifecycle

ActivityResultLauncher must be registered before the Activity reaches the STARTED state. In the proxy Activity, it’s registered at the property level — before onCreate() is even called:
class SeonVerificationActivity : ComponentActivity() {
    // Registered at property level (before STARTED lifecycle state)
    private val verificationLauncher = registerForActivityResult(StartActivityForResult()) { result ->
        resolveResult(result.resultCode, result.data)
        finish()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Launcher is already registered, safe to use
        OrchestrationService.instance.startVerificationFlow(verificationLauncher, applicationContext)
    }
}
This is why the proxy Activity pattern is essential — it provides a fresh lifecycle boundary for each verification.

Common Platform Differences

AspectiOSAndroid
InitializationState held in Swift singletonConfig passed directly to OrchestrationService
Error handlingFlutterResult with FlutterErrorFlutterResult with FlutterError
Thread contextExplicit main thread dispatchActivity lifecycle ensures UI thread
Verification UIUINavigationControllerTransparent proxy Activity

Verification Result Mapping

Both platforms map native SDK result enums to the common SeonVerificationStatus enum:
enum SeonVerificationStatus {
  completed,
  completedSuccess,
  completedPending,
  completedFailed,
  interruptedByUser,
  error,
  missingLocationPermission,  // Android-specific
}

Verification UI

The verification flow on both platforms occurs within a WebView context. This is important to understand when:
  • Debugging UI issues in the verification flow
  • Understanding why permissions like camera and microphone are required
  • Troubleshooting Content Security Policy (CSP) or network-related issues
For security reasons, the SEON SDK actively detects simulators and emulators and may refuse to operate. Always test on real physical devices.

Testing Considerations

  • Debug builds may have different SDK behavior
  • Always test release builds before shipping
  • Permissions may behave differently in debug mode

Native SDK References

For platform-specific details beyond the Flutter wrapper, see the native SDK documentation: