Release notes, Releases Flutter SDK

Migration Guide

Migration to 4.22.0

Three independent areas changed: OnboardingSessionConfiguration parameter names, the standalone faceMatch(), and theming on Android.

Renamed positive800 color palette token on Android

The positive800 key in the theme's colorPalette is now positive750, matching the palette exported from the upcoming Incode Studio product.

"colorPalette": {
  "positive50": "#E4FBF0",
  "positive400": "#189F60",
  "positive500": "#189F60",
-  "positive800": "#0C5030"
+  "positive750": "#0C5030"
}

Theme JSON that still uses positive800 silently falls back to the default, because unknown keys are ignored during parsing. Rename the key to keep your customization applied.

Stricter theme JSON parsing on Android

Color values must be quoted strings, and a [light, dark] pair must not be empty. Values that previously parsed by accident — an unquoted number such as 123456, a boolean, or [] — are now rejected when the theme is parsed.

 "colorPalette": {
-  "brand500": 123456,
+  "brand500": "#01E240",
-  "gray500": [],
+  "gray500": ["#60667C", "#A3A8B8"]
 }

setTheme takes the theme as a JSON String and has no error callback, so nothing tells you at runtime that a value was rejected — on Android an invalid theme is simply not applied. With the stricter parsing a single bad value is enough to drop the whole theme and fall back to the defaults, so validate your JSON before shipping it.

OnboardingSessionConfiguration parameters renamed

userRegion is now region, and onboardingValidationModules is now validationModules.

  OnboardingSessionConfiguration(
-   userRegion: 'ALL',
-   onboardingValidationModules: [OnboardingValidationModule.id],
+   region: 'ALL',
+   validationModules: [OnboardingValidationModule.id],
  );

This affects every entry point that takes an OnboardingSessionConfiguration: startOnboarding(), startWorkflow(), startFlow(), startNewOnboardingSection() and setupOnboardingSession().

region no longer defaults to ALL. Omitting it previously sent ALL; it is now left unset and the SDK default applies. If you relied on the old behaviour, pass it explicitly:

  OnboardingSessionConfiguration(
-   // userRegion omitted — implicitly "ALL"
+   region: 'ALL',
  );

region is Android only — iOS has no region parameter and ignores it.

getUserScore and the onUserScoreFetched callback are now served by Incode's shared cross-platform bridge, so both platforms return the same data in the same shape. Most of the changes below follow from that.

New required podspec source on iOS

The plugin now depends on IncodeBridgeCommon, which is published to its own private spec repository. Add it as a source to your Podfile:

 source 'https://cdn.cocoapods.org/'
 source 'git@github.com:Incode-Technologies-Example-Repos/IncdDistributionPodspecs.git'
+source 'git@github.com:Incode-Technologies-Example-Repos/IncodeBridgeCommonPodspecs.git'

Score values no longer include the /100 suffix

Scores are now the raw value the server returned — 80.5 instead of 80.5/100 — in both getUserScore results and the onUserScoreFetched callback. On Android, a score whose status was manual previously came through as a localized "needs review" phrase instead of a number; it is now always the numeric score.

If you displayed the value directly, append the suffix yourself:

- Text('Score: ${result.overall?.value}')
+ Text('Score: ${result.overall?.value}/100')

iOS already reported raw scores, so only Android behavior changes here.

fetchMode now defaults to accurate on Android

Omitting fetchMode previously selected UserScoreFetchMode.fast on Android and accurate on iOS. Both platforms now default to accurate. To keep the previous Android behavior, pass it explicitly:

  IncodeOnboardingSdk.getUserScore(
+   fetchMode: UserScoreFetchMode.fast,
    onSuccess: (UserScoreResult result) { ... },
    onError: (String error) { ... },
  );

getUserScore reports unified error codes

On iOS, onError previously received the native SDK's own error string. Both platforms now deliver one of the IncodeSdkFlowError codes, so you can convert instead of matching on messages:

  onError: (String error) {
-   print('getUserScore failed: $error');
+   switch (error.toIncodeSdkFlowError()) {
+     case IncodeSdkFlowError.userScoreFailed:
+       // No score available for this session.
+       break;
+     case IncodeSdkFlowError.userCancelled:
+       // Android only; this call presents no UI on iOS.
+       break;
+     default:
+       break;
+   }
  },

A session that produced no score — for example a submit-only session — previously completed through onSuccess with an empty result on Android. It now reports userScoreFailed. If you treated an empty result as a valid outcome, move that handling into onError.

startWorkflow reports error codes

startWorkflow's onError previously received the native SDK's error message. It now receives an IncodeSdkFlowError code, as documented, so convert it instead of matching on or displaying the message:

  onError: (String error) {
-   print('startWorkflow failed: $error');
+   switch (error.toIncodeSdkFlowError()) {
+     case IncodeSdkFlowError.permissionsDenied:
+       // The user denied a permission the Workflow needs.
+       break;
+     case IncodeSdkFlowError.sslPinningFailed:
+       break;
+     default:
+       break;
+   }
  },

If you showed error to users, map the code to your own text; the native message is no longer passed. startOnboarding, startFlow, and the section methods are unchanged and still pass the message, apart from the new unknownModule code below.

Unrecognized modules report unknownModule

A flow configuration naming a module the wrapper does not recognize, such as a stale name left over from a rename, was previously skipped: the flow ran without that step and still completed through onSuccess. startOnboarding and startOnboardingSection now stop and call onError with unknownModule instead.

  onError: (String error) {
    if (error == 'unknownModule') {
      // The flow configuration names a module this SDK version does not support.
    }
  },

If you build the flow configuration from data you do not control, such as a remote config, make sure it contains only module names this SDK version supports, or handle unknownModule in onError.

UserScoreResult sections are now structured objects

overall, faceRecognition, liveness and idValidation were {value, status} pairs of a private type. They are now public types that carry each section's full breakdown, and governmentValidation has been added.

Existing code keeps compiling. Every section still answers value and status, which return its overall score:

result.idValidation?.value    // '92'
result.idValidation?.status   // UserScoreStatus.ok

Newly available, if you want it: the photoSecurityAndQuality, idSpecific and ocrValidation check lists, plus livenessScore, photoQuality, existingUser and recognitionConfidence. See Results for the full structure.

The onUserScoreFetched callback now populates these too, for whichever modules the flow ran. Sections that were not evaluated stay null and their checklists are empty.

Fixed a crash on iOS when a score status was warn or unset

The iOS wrapper previously sent the Swift case name warning rather than the documented warn, and an empty string for a status the SDK left unset. UserScoreResult.fromJson threw ArgumentError on both, so any score containing a warn status crashed while parsing. Statuses are now always one of the documented values, and an unset status is null. No action is needed.

ApprovalResult has a new error field

ApprovalResult now carries error, a String? holding the module-level error reported by the native SDK, taken from IncodeSdkFlowError. It is null when the module reported no error, and always null on Android, whose native result has no equivalent field.

The field is additive: the positional constructor takes it as an optional fourth argument, so existing ApprovalResult(success, uuid, customerToken) calls keep working.

onApproveCompleted: (ApprovalResult result) {
  if (result.error != null) {
    print('Approval reported ${result.error}');
  }
},

uuid and customerToken are now null on iOS instead of empty strings

ApprovalResult.uuid and ApprovalResult.customerToken have always been declared String?, but iOS reported them as "" when the user was not approved. Both platforms now report null, matching the declared type and Android's behavior.

If you tested for empty strings, test for null instead:

// Before
if (result.uuid != '') { … }

// After
if (result.uuid != null) { … }

approve callbacks fire exactly once on both platforms

Each run settles exactly once, through onSuccess, onUserCancelled, or onError. On iOS, onSuccess was previously delivered from an internal section-completed event and could fail if the approval module had not reported; that path is gone.

onError now receives two arguments — the error code and a human-readable message — instead of a single string. forceApproval became optional and defaults to false.

// Before
IncodeOnboardingSdk.approve(
  forceApproval: false,
  onSuccess: (ApprovalResult result) { … },
  onError: (String error) {
    print('Approve error: $error');
  },
);

// After
IncodeOnboardingSdk.approve(
  onSuccess: (ApprovalResult result) { … },
  onError: (String code, String message) {
    print('Approve error: $code — $message');
  },
  onUserCancelled: () { … },
);

An approval that ran but did not approve the user is still delivered to onSuccess, with result.success == false. Only userCancelled and flow-level failures reach onUserCancelled / onError. If onUserCancelled is omitted, cancellation is reported to onError with the code userCancelled.

DocumentScan.showDocumentProviderOptions is deprecated — migrate to documentSources

showDocumentProviderOptions maps to the deprecated native chooser flags and is not applied by the V2 UI. Use the new documentSources parameter, which works with both the V1 and V2 UI and lets you list the exact capture sources offered to the user.

 flowConfig.addDocumentScan(
   documentType: DocumentType.addressStatement,
-  showDocumentProviderOptions: false,
+  documentSources: [DocumentSource.camera],
 );
 flowConfig.addDocumentScan(
   documentType: DocumentType.addressStatement,
-  showDocumentProviderOptions: true,
+  documentSources: [
+    DocumentSource.camera,
+    DocumentSource.photoUpload,
+    DocumentSource.fileUpload,
+  ],
 );

showDocumentProviderOptions still compiles and is ignored when documentSources is provided. If neither is set, the native SDK default applies. See the Android migration guide.

Affects the standalone faceMatch() only. The FaceMatch module result is unchanged.

faceMatch() parameter faceMatchType renamed to matchType

Affects the standalone faceMatch() only. The FaceMatch module result is unchanged.

- IncodeOnboardingSdk.faceMatch(faceMatchType: FaceMatchType.someValue, ...);
+ IncodeOnboardingSdk.faceMatch(matchType: FaceMatchType.someValue, ...);

faceMatch()'s onError now receives a code, message and cause

The callback signature changed from Function(String error) to Function(String code, String message, PlatformException? cause),

  IncodeOnboardingSdk.faceMatch(
-   onError: (String error) {
-     print('faceMatch failed: $error');
+   onError: (String code, String message, PlatformException? cause) {
+     print('faceMatch failed: $code - $message');
    },
    ...
  );

code is faceMatchError, or userCancelled on Android when no onUserCancelled callback is supplied.

For failures other than cancellation, onError previously received the native error text. That text is now in message; code carries faceMatchError.

Confidence scores of -1 are null on Android

The native SDK returns -1 for confidence, nfcVsIdConfidence and nfcVsSelfieConfidence when the image needed for the comparison was never uploaded. That -1 used to reach you as if it were a score. They now return null instead, matching iOS.

- if (result.confidence == -1) { /* nothing to compare */ }
+ if (result.confidence == null) { /* nothing to compare */ }

A 0 is unaffected — it is a real "no match" score.

otpVerificationEnabled renamed to otpVerification

The parameter on the Phone and Email modules now uses the native SDK's name.

- flowConfig.addPhone(otpVerificationEnabled: true);
+ flowConfig.addPhone(otpVerification: true);

- flowConfig.addEmail(otpVerificationEnabled: true);
+ flowConfig.addEmail(otpVerification: true);

The module constructors take the same new name:

- PhoneModule(otpVerificationEnabled: true)
+ PhoneModule(otpVerification: true)

- EmailModule(otpVerificationEnabled: true)
+ EmailModule(otpVerification: true)

Omitting the parameter leaves the native SDK setting in place rather than forcing it off. In practice the native default is also off, so this only matters if your app configures the SDK-level OTP flag itself.

PhoneNumberResult.phone is now nullable

phone changed from String to String?. The value is absent when the SDK captured nothing — for example when the user cancelled — so the old non-nullable type could not represent the real payload.

- onAddPhoneNumberCompleted: (result) => print(result.phone.length),
+ onAddPhoneNumberCompleted: (result) => print(result.phone?.length ?? 0),

defaultRegionPrefix is now range-checked

PhoneModule.defaultRegionPrefix accepts 1–9999. Values outside that range are ignored and the device's own region prefix is used, which is what the SDK documents. Previously an out-of-range value was dropped on Android but passed through on iOS.

Migration to 4.21.0

Migration to 4.21.0

iOS: Geolocation failures on iOS are delivered through onGeolocationCompleted for skippable modules instead of onError.

A skipped, denied, or unavailable location no longer ends the flow on iOS. It's reported via GeoLocationResult.error instead. See Results.

No change needed to compile. If your onError handled this case, move that logic to onGeolocationCompleted:

 onGeolocationCompleted: (GeoLocationResult result) {
+    if (result.error != null) return handleLocationUnavailable();
     saveAddress(result);
 },
 onError: (String error) {
-    handleLocationUnavailable();
     handleFlowError(error);
 },

New IncodeSdkFlowError.locationUnavailable case

Add this case to any exhaustive switch on IncodeSdkFlowError; it won't compile otherwise.

The user-cancel tracking event is now userCanceled (Android only)

The Android SDK reports the user-cancel tracking event as userCanceled. It was userCancelled. The new spelling matches the other SDK events and the iOS SDK.

If you compare the event string delivered to onEvents, update it:

  onEvents: (result) {
-   if (result.event == 'userCancelled') {
+   if (result.event == 'userCanceled') {
      handleUserCancel();
    }
  },

Also update every dashboard query, saved report, or server-side rule that matches the literal userCancelled.

This does not affect the onUserCancelled callback, which is unchanged.

Update the Signature V2 title and description string overrides (Android only)

Signature V2 uses dedicated string resources for the title and description. V1 continues to use the existing resources.

If you enable V2 and override the V1 strings, add these V2 overrides to your Android res/values/strings.xml:

<string name="onboard_sdk_signature_capture_title">Your title</string>
<string name="onboard_sdk_signature_capture_description">Your description</string>

Keep the V1 overrides if your integration still uses V1:

<string name="onboard_sdk_signature_title">Your title</string>
<string name="onboard_sdk_signature_description">Your description</string>

MLConsentResult.success now reflects the user's choice (iOS only)

success used to be true whenever the submission call succeeded, even if the user declined. It now reports the choice: true accepted, false declined. The consent stays optional and the flow continues either way, so treat false as "declined" rather than as a module failure.

New combinedConsentsNotReceived flow error (iOS only)

A mandatory Combined Consent with no readable text or no checkbox id is no longer silently accepted; the flow stops and onError receives combinedConsentsNotReceived. Edit the consent in Dashboard so it has a text to resolve this error. Optional consents that cannot be shown are still skipped, as before.

combinedConsentsNotReceived is never emitted on Android, but the enum is shared, so an exhaustive switch over IncodeSdkFlowError still needs a branch for it there.

Migration to 4.20.0

Migration to 4.20.0

Add the IncodeBridgeCommon CocoaPods source

iOS builds now depend on IncodeBridgeCommon. Add this source at the top of your Podfile. Access to Incode's GitHub org is required; if you do not have it, contact your Incode representative.

  source 'https://cdn.cocoapods.org/'
  source 'git@github.com:Incode-Technologies-Example-Repos/IncdDistributionPodspecs.git'
+ source 'git@github.com:Incode-Technologies-Example-Repos/IncodeBridgeCommonPodspecs.git'

Then run pod install --repo-update in the ios folder.

setTheme and setUXConfig take a JSON string

setTheme(theme:) and setUXConfig(jsonConfig:) now accept a JSON String instead of Map<String, dynamic>.

import 'dart:convert';

// Before
await IncodeOnboardingSdk.setTheme(theme: {
  'primaryColor': '#0000FF',
});
await IncodeOnboardingSdk.setUXConfig(jsonConfig: {
  'showProgressBar': true,
});

// After
await IncodeOnboardingSdk.setTheme(
  theme: jsonEncode({
    'primaryColor': '#0000FF',
  }),
);
await IncodeOnboardingSdk.setUXConfig(
  jsonConfig: jsonEncode({
    'showProgressBar': true,
  }),
);

You can also pass a JSON file's contents directly.

Removed and added parameters

  • The waitForTutorials parameter has been removed from the init() method. Configure tutorials per module with showTutorials instead: for example, flowConfig.addIdScan(showTutorials: true). See Modules.

Added IncodeSdkInitError codes

IncodeSdkInitError now includes configError and invalidInitParams in addition to simulatorDetected, testModeEnabled, and unknown. Update any exhaustive switch on the enum to handle the new cases, or keep a default. onError continues to receive the error code string; a human-readable detail may also be present in the native payload as message.

Minimum Kotlin version raised to 2.2.x

The Android SDK is compiled with Kotlin 2.2.21. Any module that compiles Kotlin source with the SDK on its classpath must use Kotlin Gradle plugin 2.2.21 or higher.

plugins {
  id 'org.jetbrains.kotlin.android' version '2.2.21'
}

Add required OkHttp packaging exclusion

Add the following exclusion to avoid duplicate-resource packaging collisions:

android {
  packaging {
    resources {
      excludes += ['META-INF/versions/9/OSGI-INF/MANIFEST.MF']
    }
  }
}

Upgrade compileSdk / AGP / Gradle wrapper

compileSdk 36

Use Android Gradle Plugin 8.9.1 or higher and Gradle 8.14.5 or higher.

distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip

Coroutines floor

If your app pins coroutines explicitly, use:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'

Migration to 4.19.0

Migration to 4.19.0

Removed and renamed parameters

  • The disableJailbreakDetection parameter has been removed from the init() method, and has no replacement. If you set it anywhere, remove it; the code will not compile until you do.
  • The IncodeSdkFlowError's jailbreakDetected error code has been replaced with integrityCompromised.

Migration to 4.18.0

Migration to 4.18.0

Renamed neutral and black color palette tokens on Android

The neutral and black keys in theme's colorPalette have been renamed:

  • neutral -> neutralLight
  • black -> neutralDark

If you provided the theme via a JSON config, rename the keys inside colorPalette:

"colorPalette": {
+  "neutralLight": "#ffffff",
-  "neutral": "#ffffff",
+  "neutralDark": "#000000",
-  "black": "#000000",
  "brand50": "#e5f0ff",
  ...
  "positive500": "#189F60",
  "positive600": "#189F60",
  "positive800": "#0C5030"
}

Theme JSON that still uses the old neutral / black keys will silently fall back to the defaults (#FFFFFF and #000000), because unknown keys are ignored during parsing. Update your JSON to use the new keys to keep your customizations applied.

Migration to 4.17.0

Migration to 4.17.0

Required type parameter in MLConsent module

The type parameter of MLConsent module is now required. Previously, omitting it on iOS caused the MLConsent screen to be skipped silently while the module resolved successfully.

Update existing calls to pass a MLConsentType:

- flowConfig.addMLConsent();
+ flowConfig.addMLConsent(type: MLConsentType.gdpr);

Valid values are MLConsentType.gdpr and MLConsentType.us.

Changed the default values of faceMaskCheck, eyesClosedCheck, headCoverCheck and lensesCheck parameters in SelfieScan and FaceAuthentication modules

The default values for the faceMaskCheck, eyesClosedCheck, headCoverCheck and lensesCheck parameters in SelfieScan and FaceAuthentication modules have been changed from false to true. If you did not previously configure these flags, they will now default to true during face capture. To preserve the previous behavior, explicitly disable these flags.

SQLCipher attribution required if you ship an open-source licenses screen on Android

Local Room databases used by the SDK are now encrypted at rest with SQLCipher for Android, distributed under a BSD-style license. The license requires consumers that redistribute binaries (i.e. your application) to reproduce its copyright notice "in the documentation and/or other materials provided with the distribution".

If your application includes an "Open Source Licenses" screen, please add the SQLCipher notice listed in Licenses. No code change is needed if you do not ship such a screen.

Migration to 4.15.0

Migration to 4.15.0

Removed localization keys on iOS

  • Removed localization keys
    • incdOnboarding.nameInfo.lastnamePlaceholder
    • incdOnboarding.ccv.invalidCCV
  • Renamed localization keys:
    • incdOnboarding.email.title -> incdOnboarding.userInformation.email.title
    • incdOnboarding.email.invalidEmail -> incdOnboarding.userInformation.email.wrongFormat
    • incdOnboarding.ccv.title -> incdOnboarding.userInformation.securityCode.title
    • incdOnboarding.nameInfo.title -> incdOnboarding.userInformation.fullName.title
    • incdOnboarding.nameInfo.subtitle -> incdOnboarding.userInformation.fullName.subtitle
    • incdOnboarding.nameInfo.namePlaceholder -> incdOnboarding.userInformation.fullName.placeholder
    • incdOnboarding.nameInfo.continue -> incdOnboarding.userInformation.continue
    • incdOnboarding.ekyc.input.label.fillYourCredentials -> incdOnboarding.ekyc.input.title

Migration to 4.14.0

Migration to 4.14.0

Removed parameters

  • Removed disableHookDetection, disableEmulatorDetection, disableRootDetection, disableVirtualEnvironmentDetection parameters from init method.
  • Removed simulatorDetected, rootDetected, hookDetected, virtualEnvDetected from IncodeSdkFlowError.

Color palette changes on Android

If you previously customized the application appearance by updating these colors from the color palette:

{
    "colorPalette": {
        "negative500": "#FF5A5F",
        "negative600": "#E71111",
        "positive500": "#189F60",
        "positive600": "#189F60"
    }
}

These keys have now been migrated to the following values:

  • negative500 -> negative400
  • negative600 -> negative500
  • positive500 -> positive400
  • positive600 -> positive500

The mentioned colors are used for the following Color Modes:

  • Icon/Status/Negative
  • Icon/Status/Positive
  • Surface/Status/Positive
  • Border/Status/Negative Static
  • Border/Status/Positive Static

ID Capture V2 - Error Screen Customization on Android

Wrong document side customization:

If you previously customized the Wrong document side error screen, add the following new string resources:

Add these strings:

<string name="onboard_sdk_id_capture_error_side_front">Capture the front side of the ID</string>
<string name="onboard_sdk_id_capture_error_side_back">Capture the back side of the ID</string>

Previous string:

<string name="onboard_sdk_id_capture_error_side">You’ve scanned the wrong document side. Please scan your document again.</string>

This string is no longer used.

No internet connection customization:

If you previously customized the No internet connection error screen, add the following new string resource:

Add this string:

<string name="onboard_sdk_no_internet_title">No internet connection</string>

Previous string:

<string name="onboard_sdk_id_capture_error_title">There was a problem</string>

The previously used string is still in use for other error screens and should be kept in your resources.

Retry button customization:

The retry button is now customized using a different string resource:

<string name="onboard_sdk_id_capture_retry">Refresh</string>

Previous string:

<string name="onboard_sdk_no_network_snackbar_action_text">Retry</string>

The previously used string is still in use for other error screens and should be kept in your resources.

Selfie V2 - Error Screen Customization on Android

No internet connection customization:

If you previously customized the No internet connection error screen, add the following new string resource:

Add this string:

<string name="onboard_sdk_no_internet_title">No internet connection</string>

Previous string:

<string name="onboard_sdk_face_scan_failed_feedback_selfie_capture_failed_title">There was a problem</string>

The previously used string is still in use for other error screens and should be kept in your resources.

String Customization on iOS

Removed localization key

incdOnboarding.curp.add.generate Renamed localization keys:

incdOnboarding.curp.generation.last.name.placeholder -> incdOnboarding.curp.generation.first.last.name.placeholder incdOnboarding.curp.generation.name.placeholder -> incdOnboarding.curp.generation.first.name.placeholder

Changes in behavior for device environment detection on Android

The behavior when detecting device environment vulnerabilities has changed:

  • Hook or virtual environment detection: Detecting hook or virtual environment vulnerabilities in the SDK triggers a native crash, which cannot be caught or handled by application code, resulting in immediate app termination.
  • Emulator and root detection: The flow is not aborted when emulator and root checks are detected. The onboarding process continues normally.

Expected crashes when running in a virtual environment on Android

It is expected that the app crashes with the following stacktraces when a virtual environment is used. For example:

java.lang.NullPointerException
    at com.incode.welcome_sdk.ThemeConfiguration$Builder.setLabelSmallStyle(SourceFile:1066)
    at com.incode.welcome_sdk.f.c(SourceFile:150)
    at com.incode.welcome_sdk.data.local.m.as(SourceFile:22)
    at com.incode.welcome_sdk.IncodeWelcome.startOnboardingSection(SourceFile:18)
java.lang.NullPointerException: Attempt to get length of null array
    at com.incode.welcome_sdk.data.IncodeWelcomeRepository.d(SourceFile:320)
    at com.incode.welcome_sdk.data.IncodeWelcomeRepository.i(SourceFile:214)

Selfie V2 - No Internet Error Screen Retry Button Change on Android

Retry button customization:

The retry button label shown on the Selfie Scan no internet error screen now uses a dedicated string resource:

<string name="onboard_sdk_face_scan_retry">Refresh</string>

Previous string:

<string name="onboard_sdk_try_again">Try again</string>

If you override onboard_sdk_try_again to customize the retry button on the no internet screen, you must now override onboard_sdk_face_scan_retry instead. The onboard_sdk_try_again string is still used for other retry scenarios.

Selfie V2 - Capture-Only Mode Success Screen Text Change on Android

Success label customization:

In capture-only mode, the Selfie Scan success screen now uses a different string resource:

<string name="onboard_sdk_face_captured">Face captured!</string>

Previous string:

<string name="onboard_sdk_enroll_success">Success!</string>

The previously used string is still in use for non-capture-only mode and should be kept in your resources.

ID Capture and Selfie V2 - Permission Open Settings Screen Text Change on Android

Open settings button customization:

The Open settings label shown on the Permission open settings screen now uses a dedicated string resource:

<string name="onboard_sdk_permission_allow_permission_action">Allow permission</string>

Previous string:

<string name="onboard_sdk_permission_open_setting_action">Open settings</string>

The previously used string is still in use for the Geolocation module and should be kept in your resources.

Migration to 4.13.0

Migration to 4.13.0

Upload error screen customization on Android

If you previously customized the upload error screen, add the following new string resource:

Add this string: `````Scan your ID```

Previous string: ````Scan your ID```

This string is now used only for customizing the ID Capture V2 tutorial screen title.

Changed default values in FaceMatch module config on Android (optional)

With the move to UxV2, the showUserExists config is now false by default.

Migration to 4.12.0

To keep using methods addFace, removeFace, getFaces and setFaces on iOS platform, please migrate to Flutter SDK variant '-l'.

 onboarding_flutter_wrapper:
  git:
    url: git@github.com:Incode-Technologies-Example-Repos/IncdOnboardingFlutter.git
-    ref: release/[VERSION]
+    ref: release/[VERSION]-l

Parameter Updates in IdScan module

  • Remove usage of enableRotationOnRetakeScreen (this parameter has been removed).
  • Replace showRetakeScreen with showRetakeScreenForManualCapture.
  • Replace showAutoCaptureRetakeScreen with showRetakeScreenForAutoCapture.

Update string resources for the "Need Help" screen in the IdScan v2 module on Android

The "Need Help" screen has been redesigned on Android, and the customizable strings have been replaced. If you override any of the following strings in your app, replace them with the new ones listed below.

No action is required if you do not override these strings.

Replaced string resources

Replace overrides of:

<string name="onboard_sdk_id_capture_help_title">Need help?</string>
<string name="onboard_sdk_id_capture_help_subtitle">Some considerations</string>
<string name="onboard_sdk_id_capture_help_manual_photo_button_text">Take the photo manually</string>
<string name="onboard_sdk_id_capture_help_align_title">Center your document in the frame</string>
<string name="onboard_sdk_id_capture_help_align_subtitle">The photo will be taken automatically</string>
<string name="onboard_sdk_id_capture_help_blur_title">Avoid blurriness on the document</string>
<string name="onboard_sdk_id_capture_help_blur_subtitle">Zoom in and out, or tap on the document</string>
<string name="onboard_sdk_id_capture_help_glare_title">Avoid glare on the document</string>
<string name="onboard_sdk_id_capture_help_glare_subtitle">Find a better lighting to avoid reflections</string>
<string name="onboard_sdk_id_capture_help_darkness_title">Avoid darkness on the document</string>
<string name="onboard_sdk_id_capture_help_darkness_subtitle">Find a place with better lighting</string>

with:

<string name="onboard_sdk_id_capture_common_issues_title">Common issues</string>
<string name="onboard_sdk_id_capture_common_issues_glare_title">Glare present</string>
<string name="onboard_sdk_id_capture_common_issues_glare_subtitle">Tilt the ID slightly up or down to minimize the reflection</string>
<string name="onboard_sdk_id_capture_common_issues_blur_title">Blur present</string>
<string name="onboard_sdk_id_capture_common_issues_blur_subtitle">Move ID further away or closer to your phone until the image is focused</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_title">Info is not readable</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_subtitle">Minimize camera shake by holding your phone steady</string>
<string name="onboard_sdk_id_capture_common_issues_try_again_button">@string/onboard_sdk_try_again</string>

Upgrade compileSdk on Android

With the update of the internal CameraX dependencies, you will need to upgrade your project's compileSdk to level 35:

compileSdk 35

Update Gradle Wrapper on Android

Android Gradle Wrapper 8.6.0 requires Gradle 8.7 or higher. Update your Gradle wrapper configuration in gradle/wrapper/gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip

Migration to 4.10.0

E2EE variant removed

RN SDK 'e2ee' variant is no longer distributed, as e2ee functionality is now offered in a standard Flutter SDK variant.

Android optional dependencies

For Android, if you use any of the following optional dependencies, make sure to update to the latest versions

implementation 'com.incode.sdk:video-streaming:1.6.0'
implementation 'com.incode.sdk:extensions:1.2.1'
implementation 'com.incode.sdk:model-face-recognition:3.5.1'
implementation 'com.incode.sdk:model-id-face-detection:3.5.1'
implementation 'com.incode.sdk:model-liveness-detection:3.2.1'

Android minSdk changes

For Android, if you use the video-streaming dependency, you need to upgrade your minSdk to 24 or higher. The requirement is coming from the OpenTok dependency, which now requires a minimum SDK version of 24. This update is necessary to ensure compatibility with the 16KB page size support mandated by Google starting from November 1st 2025. More info.

Migration to 4.9.0

Optional dependencies

For Android, if you use this optional dependency, make sure to update to the latest versions:

implementation 'com.incode.sdk:extensions:1.2.1'

Updated resource name

If you wanted to customize the logo at the top of the IdScan V2 module, you needed to override the incode logo resource: onboard_sdk_incode_logo.xml.
This resource was not intended to be customizable, so please update your customizations to the new resource name: onboard_sdk_logo_top.xml. By default, this resource is an empty 1x1 image, and you can customize it to your own logo.

Migration to 4.7.0

For Android, if you use any of the following optional dependencies, make sure to update to the latest versions

implementation 'com.incode.sdk:model-face-recognition:3.5.0'
implementation 'com.incode.sdk:model-id-face-detection:3.5.0'

The qr-face-login dependency is no longer available and has been removed in this version of the SDK. Please update your project configuration accordingly.
Remove the qr-face-login dependency from your build.gradle:

Migration to 4.6.0

  • Update Android minSdkVersion in you Android project's build.gradle:
  buildscript {
    ext {
-    minSdkVersion = 21
+    minSdkVersion = 23
    }
  }

Remove com.incode.sdk:camera:1.1.0 dependency in your app’s build.gradle file:

  dependencies {
-    implementation 'com.incode.sdk:camera:1.1.0'
  }

Migration to 4.4.0

  • To enable the new ID capture experience on Android, add the com.incode.sdk:camera:1.1.0 dependency to your app’s build.gradle file:
  dependencies {
+    implementation 'com.incode.sdk:camera:1.1.0'
  }
  • If you are using NFC variant of the SDK follow the steps below to enable NFC scanning on iOS:
  1. Turn on Near Field Communication Tag Reading under the Capabilities tab for the project’s target. This step:

    • Adds the NFC tag-reading feature to the App ID.
    • Adds the Near Field Communication Tag Reader Session Formats Entitlement to the entitlements file.
  2. Add the NFCReaderUsageDescription key as a string item to the Info.plist file. For the value, enter a string that describes the reason the app needs access to the device’s NFC reader. If the app attempts to read a tag without providing this key and string, the app will crash.

  3. Add interface for interacting with an ISO 7816 tag to App's Info.plist:

<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
   <array>
      <string>A0000002471001</string>
      <string>A0000002472001</string>
      <string>00000000000000</string>
   </array>

NOTE
If your app supports devices with iOS prior to 13.0, you will also need to set CoreNFC.framework and CryptoTokenKit.framework as an optional frameworks:

  • Select your app target
  • Under Build Phases -> Link Binary With Libraries add: CoreNFC.framework, CryptoTokenKit.framework and SwiftUI.framework libraries if they are already not on the list.
  • And finally, for all three libraries, under Status, select Optional.

Note that even though NFC Scan module will not be performed on devices with iOS version older than 13, these steps are required because otherwise the app will crash on launch time.

Example app migration

To run the example app, follow these steps:

  1. Navigate to root of the example folder. Create .env file. The file is added in .gitignore so it won't be pushed to the repository. It is used to store your own credentials. Example of the .env file content:
# Demo
DEMO_API_URL=YOUR_API_URL
DEMO_API_KEY=YOUR_API_KEY
DEMO_COMBINED_CONSENT_ID=YOUR_COMBINED_CONSENT_ID
DEMO_WORKFLOW_CONFIGURATION_ID=YOUR_WORKFLOW_CONFIGURATION_ID
DEMO_FLOW_CONFIGURATION_ID=YOUR_FLOW_CONFIGURATION_ID
DEMO_DEEP_LINK=YOUR_DEEP_LINK
    
# SaaS
SAAS_API_URL==YOUR_API_URL
SAAS_API_KEY=YOUR_API_KEY
SAAS_COMBINED_CONSENT_ID=YOUR_COMBINED_CONSENT_ID
SAAS_WORKFLOW_CONFIGURATION_ID=YOUR_WORKFLOW_CONFIGURATION_ID
SAAS_FLOW_CONFIGURATION_ID=YOUR_FLOW_CONFIGURATION_ID
SAAS_DEEP_LINK=YOUR_DEEP_LINK
  1. Run flutter pub get to install dependencies.
  2. Run the following commands to generate corresponding files for those env values:
  flutter pub run build_runner clean
  flutter pub run build_runner build --delete-conflicting-outputs
  1. The mandatory values to run the app properly are apiKey and apiUrl. Replace the other values in home.dart based on your needs.
  2. Run the app.

Migration to 4.3.0

Migration to 4.3.0
  • iOS integration requires Podfile update and SSH access being setup on the machine. Add these lines to the Podfile:
+ source 'https://cdn.cocoapods.org/'
+ source 'git@github.com:Incode-Technologies-Example-Repos/IncdDistributionPodspecs.git'

If you don't have access to the Incode's GitHub repo and SSH setup on the machine, please contact your Incode representative for support.

Migration to 3.2.0

Migration to 3.2.0

compileSdk and/or compileSdkVersion should be updated to 34.

Migration to 3.0.0

Migration to 3.0.0
  1. Remove core-light dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.6.2' // Required core dependency
}

com.incode.sdk:core-light dependency is now part of the Flutter SDK itself.

  1. Gradle versions should be updated to 7.+, ie. :
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.2.0'
+        classpath 'com.android.tools.build:gradle:7.4.2'
     }

Update gradle distributionUrl in your gradle-wrapper.properties:

-        distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
+        distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

Migration to 2.8.0

Migration to 2.8.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.6.1' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.6.2' // Required core dependency
}

Migration to 2.7.0

Migration to 2.7.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.5.1' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.6.1' // Required core dependency
}
  1. The following dependencies are optional and needed only in very specific use cases.
    Make sure you are using the features they provide before adding the dependencies below. Update dependency in your Android project's build.gradle:
dependencies {
+ implementation 'com.incode.sdk:kiosk-login:1.3.1' // Optional kiosk-login dependency is only necessary if you are using Kiosk Login feature of the SDK.
+ implementation 'com.incode.sdk:model-liveness-detection:3.0.0' // Optional model-liveness-detection dependency is only necessary if you are using liveness detection feature that runs locally on device. This feature can be used within IncodeOnboardingSdk.startFaceLogin method
+ implementation 'com.incode.sdk:model-face-recognition:3.0.0' // Optional model-face-recognition dependency is only necessary if you are using face recognition feature that runs locally on device. This feature can be used within IncodeOnboardingSdk.startFaceLogin method
}

Migration to 2.6.0

Migration to 2.6.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.5.0' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.5.1' // Required core dependency
}

Migration to 2.4.0

Migration to 2.4.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.4.0' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.5.0' // Required core dependency
}
  1. Update compileSdkVersion and targetSdkVersion in your Android project's build.gradle to 33.

  2. Bumped minSdkVersion into 21 from 17

Migration to 2.2.0

Migration to 2.2.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.3.0' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.4.0' // Required core dependency
}

Migration to 2.1.0

Migration to 2.1.0
  1. Update dependency in your Android project's build.gradle:
dependencies {
- implementation 'com.incode.sdk:core-light:2.2.0' // Required core dependency
+ implementation 'com.incode.sdk:core-light:2.3.0' // Required core dependency
}

Migration to 2.x

Migration to 2.x
  1. Added setupOnboardingSession that replaces creatingNewOnboardingSession and setOnboardingSession
- IncodeOnboardingSdk.creatingNewOnboardingSession
+ IncodeOnboardingSdk.setupOnboardingSession
- IncodeOnboardingSdk.setOnboardingSession
+ IncodeOnboardingSdk.setupOnboardingSession
  1. iOS app setup changed - it is no longer needed to add these lines to the Podfile, so these should be removed when upgrading to 2.x:
-source 'https://github.com/CocoaPods/Specs.git'
-source 'git@github.com:Incode-Technologies-Example-Repos/IncdDistributionPodspecs.git'