kyc_workflow 2.0.28 copy "kyc_workflow: ^2.0.28" to clipboard
kyc_workflow: ^2.0.28 copied to clipboard

Digio kyc workflow plugin

Digio KYC Workflow Plugin #

A Flutter plugin for running Digio's KYC, eSign, mandate, UPI, and RPD flows on Android and iOS.

The plugin exposes two ways of using the Digio SDK from your app. Pick the one that fits your use case:

Mode When to use it Supported flows Entry point
Workflow You want the full Digio-orchestrated journey. Your backend has created a workflow request and issued you a documentId + tokenId. KYC, Mandate, UPI, RPD, eSign (via OTP / Fingerprint / Face / Iris) KycWorkflow.start(...)
Stateless You want a pure native SDK experience for a standalone task. Your backend issues a JWT that carries the Digio credentials — the SDK reads the token and handles the rest. Selfie (Android + iOS) KycWorkflow.startStateless(...)

Table of Contents #


Android setup #

Digio SDK supports Android 7.0 and above (SDK level 24+).

1. Root build.gradle #

Add the required Maven repositories:

allprojects {
  repositories {
    ...
    maven { url 'https://jitpack.io' }
    maven {
      url = uri("https://pkgs.dev.azure.com/eMudhraTrustService/b81ae285-cb60-4000-8c39-394db16f2a75/_packaging/eMudhraEsignAAR/maven/v1")
    }
  }
}

2. App-level dependency (android/app/build.gradle) #

implementation 'com.github.digio-tech:protean-esign:v3.12'

3. App build.gradle configuration #

android {
    compileSdk = 35

    defaultConfig {
        minSdk = 26
    }

    buildTypes {
        release {
            signingConfig signingConfigs.debug
            minifyEnabled true
        }
        debug {
            signingConfig signingConfigs.debug
            minifyEnabled true
        }
    }

    buildFeatures {
        viewBinding true
        dataBinding true
    }

    dependencies {
        implementation 'com.github.digio-tech:protean-esign:v3.12'
    }
}

4. Android Gradle Plugin (android/settings.gradle) #

plugins {
  ...
  id 'com.android.application' version '8.7.1' apply false
  ...
}

5. Project-level build.gradle #

Add the Kotlin plugin at the project level:

buildscript {
    ext.kotlin_version = "1.9.24"
    dependencies {
        classpath("com.android.tools.build:gradle:8.4.0")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
    }
}

6. Manifest permissions #

<!-- Required for Video KYC -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

<!-- Required for geotagging -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Required for ID card analysis, selfie and face match -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

A fintech Android app cannot access these permissions: READ_EXTERNAL_STORAGE, READ_MEDIA_IMAGES, READ_CONTACTS, ACCESS_FINE_LOCATION, READ_PHONE_NUMBERS, READ_MEDIA_VIDEOS.

Common Android issues #

Build error due to a theme conflict — add tools:replace="android:theme" under your <application> tag:

<application
    ...
    tools:replace="android:label,android:theme"
    ...>
    ...
</application>

Crash related to the AppCompat theme while using eSign — set an AppCompat theme on the <application> tag:

<application
    ...
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    ...>
    ...
</application>

ProGuard rules #

Always test the release build before shipping. Add these rules to your ProGuard config:

Click to expand ProGuard rules
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}
-keepattributes JavascriptInterface
-keepattributes *Annotation*
-keepattributes Signature
-optimizations !method/inlining/*
-keeppackagenames
-keepnames class androidx.navigation.fragment.NavHostFragment
-keep class * extends androidx.fragment.app.Fragment{}
-keepnames class * extends android.os.Parcelable
-keepnames class * extends java.io.Serializable
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-dontwarn androidx.databinding.**
-keep class androidx.databinding.** { *; }
-keepclassmembers class * extends androidx.databinding.** { *; }
-dontwarn org.json.**
-keep class org.json** { *; }
-keep public class org.simpleframework.**{ *; }
-keep class org.simpleframework.xml.**{ *; }
-keep class org.simpleframework.xml.core.**{ *; }
-keep class org.simpleframework.xml.util.**{ *; }
-dontwarn com.google.android.gms.**
-keep class com.google.android.gms.** { *; }
-keep class com.google.android.material.** { *; }
-dontwarn org.simpleframework.**
-keepattributes ElementList, Root
-keepclassmembers class * {
    @org.simpleframework.xml.* *;
}
-keep class org.spongycastle.** { *; }
-keep class com.ecs.rdlibrary.request.** { *; }
-keep class com.ecs.rdlibrary.response.** { *; }
-keep class com.ecs.rdlibrary.utils.** { *; }
-keep class com.ecs.rdlibrary.ECSBioCaptureActivity { *; }
-keep class org.simpleframework.xml.** { *; }
-keepattributes Exceptions, InnerClasses
-keep class com.google.android.gms.location.LocationSettingsRequest$Builder { *; }
-keepnames class ** { *; }
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
-keepattributes AnnotationDefault
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}
-dontwarn javax.annotation.**
-dontwarn kotlin.Unit
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
-keep class * extends androidx.databinding.DataBinderMapper
-dontwarn kotlin.jvm.internal.SourceDebugExtension

-dontwarn org.xmlpull.v1.**
-keep class org.xmlpull.v1.** { *; }
-keep class in.digio.sdk.gateway.interfaces.FeatureRegistrationInterface$DefaultImpls { *; }

-keep class javax.xml.bind.annotation.** { *; }
-dontwarn javax.xml.bind.annotation.**
-keep class com.ecs.cdslxsds.ESignProcessorResponse { *; }

-dontwarn org.xmlpull.v1.XmlPullParser
-dontwarn android.content.res.XmlResourceParser

-keep class in.digio.sdk.gateway.interfaces.FeatureRegistrationInterface$DefaultImpls { *; }
-dontwarn java.lang.invoke.StringConcatFactory
-keep public class com.digio.two_way_sdk.** {
    public *;
}
-keep class com.digio.two_way_sdk.** { *; }
-keep class androidx.databinding.** { *; }
-keep class androidx.viewbinding.** { *; }
-keep public class * extends androidx.**
-keep public class com.google.android.material.** { *; }
-keep public class androidx.** { public *; }

# emudhra
-keep class com.emudhra.** { *; }
-keep interface com.emudhra.** { *; }
-keepclassmembers class com.emudhra.** {
    native <methods>;
}
-dontwarn com.emudhra.**

# Jackson dataformat XML (used by emudhra at runtime via XmlMapper)
-keep class com.fasterxml.jackson.** { *; }
-keepnames class com.fasterxml.jackson.** { *; }
-dontwarn com.fasterxml.jackson.**

# Woodstox - StAX implementation backing jackson-dataformat-xml.
# FactoryFinder uses Class.forName via META-INF/services lookup; the impl
# classes must not be obfuscated or shrunk away.
-keep class com.ctc.wstx.** { *; }
-keep class org.codehaus.stax2.** { *; }
-dontwarn com.ctc.wstx.**
-dontwarn org.codehaus.stax2.**

# StAX API surfaces referenced via reflection
-keep class javax.xml.stream.** { *; }
-dontwarn javax.xml.stream.**
-keep class * implements javax.xml.stream.XMLInputFactory
-keep class * implements javax.xml.stream.XMLOutputFactory
-keep class * implements javax.xml.stream.XMLEventFactory

-keepattributes Signature, *Annotation*, EnclosingMethod, InnerClasses

iOS setup #

No manual SDK installation is required for iOS — CocoaPods handles it. Digio SDK supports Xcode 14.0+, Swift 5.7+, and iOS 15.6+.

Info.plist permissions #

<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) would like to access your camera.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) would like to access your photo.</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) would like to access your microphone to capture video.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) would like to access your location.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) would like to access your location.</string>

LSApplicationQueriesSchemes (needed for UPI apps) #

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>phonepe</string>
    <string>gpay</string>
    <string>paytmmp</string>
    <string>bhim</string>
    <string>upi</string>
    <string>ppe</string>
</array>

Usage — Workflow mode #

Use this when your backend has created a Digio workflow request and given you a documentId and tokenId. The SDK will drive the entire journey on its own — this includes:

  • KYC (identity verification, document capture, video KYC, geotagging)
  • Mandate (eNACH / UPI mandate)
  • UPI (collect, intent)
  • RPD (Reverse Penny Drop — bank account verification)
  • eSign — with authentication via OTP, Fingerprint (FP), Face, or Iris

Which flow actually runs is decided by the workflow you configured on the Digio backend — your Flutter code just starts it.

HashMap<String, String> additionalData = HashMap<String, String>();
additionalData["dg_disable_upi_collect_flow"] = "false"; // optional, for mandate

final digioConfig = DigioConfig();
digioConfig.theme.primaryColor = "#32a83a";
digioConfig.logo = "https://your_logo_url";
digioConfig.environment = Environment.SANDBOX;
digioConfig.serviceMode = ServiceMode.OTP; // FP / FACE / IRIS / OTP
digioConfig.global = false;

final kycWorkflow = KycWorkflow(digioConfig);

kycWorkflow.setGatewayEventListener((GatewayEvent? event) {
  print("gateway event: $event");
});

final workflowResult = await kycWorkflow.start(
  "KID23010416361850266BAKNKNORLP6W",  // documentId
  "abc@gmail.com",                     // identifier (customer)
  "GWT230104163618520T2Y9IPUT2PBNC8",  // tokenId
  additionalData,
);

print('workflowResult: $workflowResult');

Usage — Stateless mode #

Stateless mode gives a pure native SDK experience. Your app tells the SDK which task to run (currently only Selfie) and passes a JWT token issued by your backend. That JWT carries the Digio credentials the SDK needs — clientSecret, transactionId, templateName, customerIdentifier, expirySeconds — so your app never has to handle them directly. The SDK decodes the token and runs the task natively.

Supported features today: SELFIE (Android + iOS).

How the JWT works #

  1. Your backend calls Digio to prepare a task (selfie capture) and gets back the credentials.
  2. Your backend wraps those credentials into a short-lived JWT and hands it to your Flutter app.
  3. Your app passes that JWT + the feature list into startStateless(...).
  4. The SDK opens the native screen, runs the task, and returns a result — no further backend calls from your Flutter code.

Example — Selfie #

import 'package:kyc_workflow/kyc_workflow.dart';
import 'package:kyc_workflow/environment.dart';
import 'package:kyc_workflow/digio_config.dart';
import 'package:kyc_workflow/stateless/stateless_config.dart';
import 'package:kyc_workflow/stateless/stateless_feature.dart';
import 'package:kyc_workflow/stateless/selfie_config.dart';

final config = StatelessConfig(
  environment: Environment.SANDBOX,
  clientId: 'YOUR_CLIENT_ID',
  token: 'JWT_FROM_YOUR_BACKEND',
  features: [StatelessFeature.SELFIE],
  selfieConfig: SelfieConfig(
    autoCapture: false,
    showInstruction: false,
    hasGeotagging: false,
    logoUrl: 'https://your_logo_url',
  ),
);

final kyc = KycWorkflow(DigioConfig());

kyc.setStatelessEventListener((event) {
  print('stateless event: screen=${event.screen}, action=${event.action}');
});

final response = await kyc.startStateless(config);
print('status: ${response.status}');
print('results: ${response.results}');
print('error: ${response.error}');

StatelessConfig fields #

Field Required Description
environment Yes (default PRODUCTION) Environment.SANDBOX for testing, Environment.PRODUCTION for live.
clientId Yes Your Digio client ID.
token Yes The JWT issued by your backend. Encodes clientSecret, transactionId, templateName, customerIdentifier, expirySeconds.
features Yes List of tasks to run. Currently: SELFIE.
selfieConfig Only if SELFIE is in features See below.

SelfieConfig fields #

Field Default Description
autoCapture false Automatically capture when the face is aligned.
showInstruction true Show the instructions screen before the camera opens.
hasGeotagging false Attach the user's location to the capture.
logoUrl null Your logo shown on the SDK screens.

StatelessResponse #

Field Description
status FlowStatus.SUCCESS, FAILED, or CANCELLED.
results List of SdkTaskResponse — one per feature you requested.
error Human-readable error string, if any.

Response codes #

The code field in the workflow response is the single source of truth — do not parse the message string.

Field Example Description
documentId DID22040413040490937VNTC6LAP8KWD Request ID passed by the parent app.
message Signing Success Human-readable status. May be Signing Failure, Failure (SDK crash), or Webpage could not be loaded (network issue after 3 retries).
code 1001 Machine-readable status — see codes below.
screen document_preview Last screen the user was on.
npciTxnId NPCI transaction ID (UPI flows).
stacktrace Crash log, present only on SDK crash.

Response code constants:

Constant Value
DigioConstants.RESPONSE_CODE_SUCCESS 1001
RESPONSE_CODE_CANCEL -1000
RESPONSE_CODE_FAIL 1002
RESPONSE_CODE_WEB_VIEW_CRASH 1003
RESPONSE_CODE_SDK_CRASH 1004

More references #

8
likes
130
points
9.75k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Digio kyc workflow plugin

Homepage

License

BSD-3-Clause (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on kyc_workflow

Packages that implement kyc_workflow