Full SDK Integration
This page describes on how to do a straightforward Incode Mobile Onboarding implementation.
Prerequisites
It is first required to Setup Environment install the SDK into the project follow the details outlined in the Setup Environment
The minimum supported Android version is 21, which supports 99.6% of devices.
The minimum supported iOS version is iOS 13, which supports 99.6% of devices.
High level
The below diagram illustrates from a high level what happens during a straightforward integration.
A full example of the straightforwrd integration can be see at this github repo. Alternatively, view the recipe.
Step 1: Initialize the Incode SDK
Fast way SDK Initialize
Before the Incode SDK can be utilized, it must be initialized. Check the following code on how to initialize the Incode SDK on each platform.
public static void IncodeSDKInitialize(Application app) {
try {
new IncodeWelcome.Builder(app, Constants.API_URL, Constants.API_KEY)
.setLoggingEnabled(true)
.build();
incodeSDKInitialized = true;
} catch (Exception exception) {
incodeSDKInitialized = false;
}
}
private void setIncodeCommonConfig() {
CommonConfig commonConfig = new com.incode.welcome_sdk.CommonConfig.Builder()
.setShowExitConfirmation(true)
.setShowCloseButton(true)
.build();
IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
func incodeSDKInitialize(api_url: String, api_key: String) {
IncdOnboardingManager.shared.initIncdOnboarding(url: api_url,
apiKey: api_key,
loggingEnabled: true,
testMode: testMode) { (success, error) in
print("IncdOnboarding SDK initialization, success: \(success == true), error: \(error?.description ?? "nil")")
self.dispatchGroup.leave()
}
}
func setIncodeCommonConfig() {
IncdOnboardingManager.shared.allowUserToCancel = true
IncdOnboardingManager.shared.idBackShownAsFrontCheck = true
IncdOnboardingManager.shared.idFrontShownAsBackCheck = true
}
const IncodeSDKInitialize = (API_URL, API_KEY) => {
IncodeSdk.initialize({
testMode: false,
apiConfig: {
url: API_URL,
key: API_KEY,
},
waitForTutorials: true,
})
.then((_) => {
startStraightforwardOnboarding();
})
.catch((e) => {
console.error('Incode SDK failed init', e);
});
};
void IncodeSDKInitialize(API_URL,API_KEY) {
IncodeOnboardingSdk.init(
apiKey: API_KEY,
apiUrl: API_URL,
onError: (String error) {
print('Incode SDK init failed: $error');
},
onSuccess: () {
onStartOnboarding();
},
);
}
// NOTE:
//
// To Initialize the SDK in Xamarin, you need to add the next code into the Native project
// that Xamarin creates.
// ANDROID
// **************************************************
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;
using Incode.Onboarding;
namespace IncodeOnboardingApplication.Droid
{
[Activity(Label = "IncodeOnboardingApplication", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
// TODO - 1 - Set environment configuration
var API_URL = "";
var API_KEY = "";
IncodeOnboarding.Current.Init(
url: API_URL,
apiKey: API_KEY,
isLoggingEnabled: true,
isTestMode: false
);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
// iOS
// **************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using Incode.Onboarding;
using UIKit;
namespace IncodeOnboardingApplication.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
// TODO - 1 - Set environment configuration
var API_URL = "";
var API_KEY = "";
IncodeOnboarding.Current.Init(
url: API_URL,
apiKey:API_KEY,
isLoggingEnabled: true,
isTestMode: false
);
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
}
function incodeSDKInitialize() {
cordova.exec(function(param) {
console.log("Success: "+param);
// start the incode session here
startSession();
}, function(err) {
console.log("Error: "+ err);
callbackError('Nothing to echo.' +err);
}, "Cplugin", "initializeSDK", [apiKey,apiUrl,loggingEnabled,testMode]); //apikey,apiurl,loggingenabled, last testmode should be false for production
}
incodeSDKInitialize(): void {
cordova.exec((param: any) => {
console.log("Success: ", param);
this.startSession();
}, (err: any) => {
console.log("Error:::: ", err);
}, "Cplugin", "initializeSDK", [Constants.API_KEY, Constants.API_URL, "true", "false", "true"]);
}
SDK Initialize with session created at backend
If you are creating the session in the backend, the API_URL needs to end with /0/ in order to let our bakcned knows how to manage the request using only the token of the session. You need to initialize the SDK in this way:
public static void IncodeSDKInitialize(Application app) {
try {
new IncodeWelcome.Builder(app, Constants.API_URL+"/0/")
.setLoggingEnabled(true)
.build();
incodeSDKInitialized = true;
} catch (Exception exception) {
incodeSDKInitialized = false;
}
}
private void setIncodeCommonConfig() {
CommonConfig commonConfig = new com.incode.welcome_sdk.CommonConfig.Builder()
.setShowExitConfirmation(true)
.setShowCloseButton(true)
.build();
IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
func incodeSDKInitialize(api_url: String, api_key: String) {
IncdOnboardingManager.shared.initIncdOnboarding(url: api_url+"/0/",
loggingEnabled: true,
testMode: testMode) { (success, error) in
print("IncdOnboarding SDK initialization, success: \(success == true), error: \(error?.description ?? "nil")")
self.dispatchGroup.leave()
}
}
func setIncodeCommonConfig() {
IncdOnboardingManager.shared.allowUserToCancel = true
IncdOnboardingManager.shared.idBackShownAsFrontCheck = true
IncdOnboardingManager.shared.idFrontShownAsBackCheck = true
}
const IncodeSDKInitialize = (API_URL, API_KEY) => {
IncodeSdk.initialize({
testMode: false,
apiConfig: {
url: API_URL+"/0/",
},
waitForTutorials: true,
})
.then((_) => {
startStraightforwardOnboarding();
})
.catch((e) => {
console.error('Incode SDK failed init', e);
});
};
void IncodeSDKInitialize(API_URL,API_KEY) {
IncodeOnboardingSdk.init(
apiUrl: API_URL+"/0/",
onError: (String error) {
print('Incode SDK init failed: $error');
},
onSuccess: () {
onStartOnboarding();
},
);
}
// Not possible to do it in Xamarin for now
function incodeSDKInitialize() {
cordova.exec(function(param) {
console.log("SDK initializeSDKWithToken Success: "+param);
startSession();
}, function(err) {
console.log("Error initializeSDK: "+ err);
}, "Cplugin", "initializeSDK", ["",apiUrlfortoken+"/0/",loggingEnabled,testMode]); //apikey,apiurl,loggingenabled, testmode should be false for production
}
incodeSDKInitialize(): void {
cordova.exec((param: any) => {
console.log("Success: ", param);
this.startSession();
}, (err: any) => {
console.log("Error:::: ", err);
}, "Cplugin", "initializeSDK", ["", Constants.API_URL+"/0/", "true", "false", "true"]);
}
Step 2: Create the session
Next, a session needs to be created in order for the data to be captured. This requires a Configuration ID, which is also known as a flow ID. To configure a flow, check out the getting started guide.
Fast way session creation
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.setRegionIsoCode("ALL")
.setConfigurationId(Constants.CONFIGURATION_ID)
.build();
return sessionConfig;
}
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
return IncdOnboardingSessionConfiguration(regionCode: "ALL",
configurationId: "PASTE__HERE_CONFIGURATION_ID")
}
function getSimpleSession() {
let sessionConfig: {
region: 'ALL',
configurationId: CONFIGURATION_ID,
};
return sessionConfig;
}
OnboardingSessionConfiguration getSimpleSession() {
// Common configs
IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
// Session config
OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(configurationId: CONFIGURATION_ID);
return sessionConfig;
}
var config = new OnboardingConfiguration()
.AddRegion("ALL")
.AddConfigurationId(CONFIGURATION_ID)
.AllowUserToCancel(true);
function startSession(){
cordova.exec(function(data) {
// Start the Incode moudles or sections from here
startOnboardingSection();
}, function(err) {
console.log(" startSession Error: "+ err);
// handle the error by showing some UI or alert.
callbackError('Nothing to echo.' +err);
}, "Cplugin", "setupOnboardingSession", [configId,null,null,null]);
}
startSession(): void {
const configId = '';
cordova.exec((data: { interviewId: any; token: any; }) => {
console.log("OnSession created Success: ", data.interviewId , " Token:" , data.token);
this.startOnboardingSection();
}, (err: string) => {
console.log(" startSession Error: ", err);
this.callbackError(err);
}, "Cplugin", "setupOnboardingSession", [Constants.CONFIGURATION_ID,null,null,null]);
}
Setup a session created at backend
If you are creating the session in the backend, you need to set the session token in order to let the SDK save all the information captured during the onboarding to that session.
You need to create a way to share that token from your backend to your frontend, usually this is done by an additional API that you need to create. Once the frontend has the token (SESSION_TOKEN_FROM_BACKEND), you just need to pass it to the SDK. You can do that in this way:
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.setRegionIsoCode("ALL")
.setExternalToken(SESSION_TOKEN_FROM_BACKEND)
.build();
return sessionConfig;
}
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
return IncdOnboardingSessionConfiguration(regionCode: "ALL",
token: SESSION_TOKEN_FROM_BACKEND)
}
function getSimpleSession() {
let sessionConfig: {
region: 'ALL',
token: SESSION_TOKEN_FROM_BACKEND,
};
return sessionConfig;
}
OnboardingSessionConfiguration getSimpleSession() {
// Common configs
IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
// Session config
OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(token: SESSION_TOKEN_FROM_BACKEND);
return sessionConfig;
}
// Not possible to do it in Xamarin for now
function startSession(){
cordova.exec(function(data) {
// Start the Incode moudles or sections from here
startOnboardingSection(); //userdefined
}, function(err) {
console.log("Error startSession: "+ err);
}, "Cplugin", "setupOnboardingSession", [null,null,null,externalToken]);
}
startSession(): void {
const configId = '';
cordova.exec((data: { interviewId: any; token: any; }) => {
console.log("OnSession created Success: ", data.interviewId , " Token:" , data.token);
this.startOnboardingSection();
}, (err: string) => {
console.log(" startSession Error: ", err);
this.callbackError(err);
}, "Cplugin", "setupOnboardingSession", [ null,null,null,Constants.TOKEN]); //TOKEN CREATED IN BACKEND HERE
}
Step 3: Configure the User Experience
The code snippet below creates an experience which the user scans their ID, the ID is processed, the Selfie is scanned, and finally face match is performed. This is the default onboarding experience and can be customized as needed.
private FlowConfig getStraightforwardFlowConfig() {
FlowConfig flowConfig = null;
try {
flowConfig = new FlowConfig.Builder()
.addID(new IdScan.Builder()
.setIdType(IdScan.IdType.ID)
.setShowIdTutorials(true)
.setWaitForTutorials(true)
.setEnableFrontShownAsBackCheck(true)
.setEnableBackShownAsFrontCheck(true)
.setIdCategory(IdCategory.FIRST)
.build())
.addProcessId(new ProcessId.Builder()
.setIdCategory(IdCategory.FIRST)
.build()
)
.addSelfieScan(new SelfieScan.Builder()
.setShowTutorials(true)
.setWaitForTutorials(true)
.setMaskCheckEnabled(true)
.setLensesCheckEnabled(true)
.build()
)
.addFaceMatch(new FaceMatch.Builder()
.setShowUserExists(false)
.build()
)
.build();
} catch (ModuleConfigurationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return flowConfig;
}
func createFlowConfiguration() -> IncdOnboardingFlowConfiguration {
let flowConfig = IncdOnboardingFlowConfiguration(waitForTutorials: true)
flowConfig.addIdScan()
flowConfig.addProcessId()
flowConfig.addSelfieScan()
flowConfig.addFaceMatch()
return flowConfig
}
function getStraightforwardFlowConfig(){
let flowConfig = [
{ module: 'IdScanFront', showTutorial: true, idType: 'id' },
{ module: 'IdScanBack', showTutorial: true, idType: 'id' },
{ module: 'ProcessId'},
{ module: 'SelfieScan', showTutorial: true, lensesCheck: false },
{ module: 'FaceMatch' },
];
return flowConfig;
}
OnboardingFlowConfiguration getStraightforwardFlowConfig(){
OnboardingFlowConfiguration flowConfig = OnboardingFlowConfiguration();
flowConfig.addIdScan(scanStep: ScanStepType.front, idType: IdType.id, showTutorials: true);
flowConfig.addIdScan(scanStep: ScanStepType.back, idType: IdType.id, showTutorials: true);
flowConfig.addProcessId();
flowConfig.addSelfieScan(showTutorials: true);
flowConfig.addFaceMatch();
return flowConfig;
}
cofig.AddIdScan(new IdScanParams(showTutorials: true), result => ProcessIdScanCallback(result));
config.AddSelfieScan(new SelfieScanParams(showTutorials: true, lensesCheck: true, maskCheckEnabled:true, brightnessThreshold: null), result => ProcessSelfieScanCallback(result));
config.AddFaceMatch(new FaceMatchParams(), result => ProcessFaceMatchCallback(result));
function startOnboardingSection(){
cordova.exec(function(winParam) {
console.log("startOnboardingSection Success: ");
finishOnboarding();//user defined
}, function(err) {
console.log("Error: "+ err);
// handle the error by showing some UI or alert.
callbackError('Nothing to echo.' +err);
}, "Cplugin", "startOnboardingSection", [
{"module":"addId","showTutorials":"true","waitForTutorials":"true",
"idCategory":"FIRST","enableBackShownAsFrontCheck":"true",
"enableFrontShownAsBackCheck":"true","autocaptureUXMode":"HOLDSTILL"},
{"module":"addSelfieScan","showTutorials":"true","waitForTutorials":"true",
"maskCheckEnabled":"true","lensesCheckEnabled":"true"},
{"module":"addFaceMatch"}]);
}
startOnboardingSection(): void{
console.log("startOnboardingSection");
cordova.exec((winParam: any) => {
console.log("startOnboardingSection Success: ");
const myObj = JSON.stringify(winParam);
console.log("myObj Success: ", myObj);
const myObj1 = JSON.parse(myObj);
console.log("data Success: ", myObj1.processIdData);
this.finishOnboarding();
}, (err: string) => {
console.log("Error: ", err);
this.callbackError(err);
}, "Cplugin", "startOnboardingSection", [
{"module":"addId","showTutorials":"false","waitForTutorials":"false","idCategory":"FIRST","enableBackShownAsFrontCheck":"true","enableFrontShownAsBackCheck":"true","autocaptureUXMode":"HOLDSTILL"},
{"module":"addSelfieScan","showTutorials":"false","waitForTutorials":"false","maskCheckEnabled":"true"},
{"module":"addFaceMatch"}]);
}
Step 4: Implement the callbacks
During the user's journey to the flow, various callbacks are executed. Custom business logic can be added in these call backs, but showing a custom screen in between steps is not supported.
private IncodeWelcome.OnboardingListener getStraightforwardOnboardingListener() {
IncodeWelcome.OnboardingListener onboardingListener = new IncodeWelcome.OnboardingListener() {
@Override
public void onOnboardingSessionCreated(String token, String interviewId, String region) {
super.onOnboardingSessionCreated(token, interviewId, region);
((MainActivity) activity).interviewId = interviewId;
}
@Override
public void onIdFrontCompleted(IdScanResult result) {
super.onIdFrontCompleted(result);
Timber.d("onIdFrontCompleted: %s", result);
}
@Override
public void onIdBackCompleted(IdScanResult result) {
super.onIdBackCompleted(result);
Timber.d("onIdBackCompleted: %s", result);
}
@Override
public void onIdProcessed(IdProcessResult result) {
super.onIdProcessed(result);
Timber.d("onIdProcessed: %s", result);
}
@Override
public void onSelfieScanCompleted(SelfieScanResult result) {
super.onSelfieScanCompleted(result);
Timber.d("onSelfieScanCompleted: %s", result);
}
@Override
public void onFaceMatchCompleted(FaceMatchResult result) {
super.onFaceMatchCompleted(result);
Timber.d("onFaceMatchCompleted: %s", result);
executeFaceMatchValidationCheck(result);
}
@Override
public void onSuccess() {
super.onSuccess();
Timber.d("onSuccess");
fetchUserScores(interviewId);
}
@Override
public void onError(Throwable error) {
super.onError(error);
Timber.d("onError: %s", error);
}
@Override
public void onUserCancelled() {
super.onUserCancelled();
Timber.d("onUserCancelled");
}
};
return onboardingListener;
}
extension MainViewController: IncdOnboardingDelegate {
func onOnboardingSessionCreated(_ result: OnboardingSessionResult) {
print("onOnboardingSessionCreated, result: \(result)")
if result.error != nil {
let interviewId = result.interviewId
}
}
func onIdFrontCompleted(_ result: IdScanResult) {
print("front IdScanResult: \(result)")
}
func onIdBackCompleted(_ result: IdScanResult) {
print("back IdScanResult: \(result)")
}
func onIdProcessed(_ result: IdProcessResult) {
print("idProcessResult: \(result)")
}
func onSelfieScanCompleted(_ result: SelfieScanResult) {
print("onSelfieScanCompleted, result: \(result)")
}
func onFaceMatchCompleted(_ result: FaceMatchResult) {
print("onFaceMatchCompleted, result: \(result)")
}
func onSuccess() {
print("onSuccess")
fetchUsetScore()
}
func onError(_ error: IncdFlowError) {
print("onError, result: \(error)")
}
func userCancelledSession() {
print("userCancelledSession")
}
}
const setupListeners = ({}) => {
// returns a callback to unregister your listener, e.g. when your screen is getting unmounted
IncodeSdk.onSessionCreated((session) => {
let interviewID = session.interviewId
});
const complete = IncodeSdk.onStepCompleted;
return [
complete({
module: 'IdScanFront',
listener: (e) => {
console.log('IdScanFront result: ', e.result);
},
}),
complete({
module: 'IdScanBack',
listener: (e) => {
console.log('IdScanBack result: ', e.result);
},
}),
complete({
module: 'ProcessId',
listener: (e) => {
console.log('ProcessId result: ', e.result);
},
}),
complete({
module: 'SelfieScan',
listener: (e) => {
console.log('SelfieScan result:', e.result);
},
}),
complete({
module: 'FaceMatch',
listener: (e) => {
console.log('FaceMatch result: ', e.result);
},
}),
];
};
useEffect(() => {
const unsubscribers = setupListeners({});
// return a function unregistering all your listeners
return () => {
unsubscribers.forEach((unsubscriber) => unsubscriber());
};
}, []);
void onSuccessCallback(){
}
void onErrorCallback(String error){
}
void onUserCancelledCallback(){
}
void onIdFrontCompletedCallback(IdScanResult result) {
print("ID Front");
print(result);
}
void onIdBackCompletedCallback(IdScanResult result) {
print("ID Back");
print(result);
}
void onIdProcessedCallback(String result) {
print("ID Process");
print(result);
}
void onSelfieScanCompletedCallback(SelfieScanResult result) {
print("Selfie Scan");
print(result);
}
void onFaceMatchCompletedCallback(FaceMatchResult result) {
print("Face Match");
print(result);
}
private void ProcessIdScanCallback(IdValidationResult result)
{
if (result != null)
{
if (result.Result == ResultCode.Success)
{
Debug.WriteLine("######## Id Scan Completed!");
Debug.WriteLine($"######## Result => {result}");
// TODO - Manage module success completion
// TODO - Save/store relevant information for future use in the app
// TODO - Save current module executed succesfully
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
Debug.WriteLine($"######## Id Scan Front Status => {result.FrontIdStatus}.");
Debug.WriteLine($"######## Id Scan Back Status => {result.BackIdStatus}.");
if(result.FrontIdStatus == IdValidationResult.ValidationStatus.Ok)
{
Debug.WriteLine($"####### Front Id Image in Base64 => {result.FrontId}.");
Debug.WriteLine($"####### Front Id Cropped Face Image in Base64 => {result.FrontIdCroppedFace}.");
}
if (result.BackIdStatus == IdValidationResult.ValidationStatus.Ok)
{
Debug.WriteLine($"####### Back Id Image in Base64 => {result.BackId}.");
}
if(result.OcrData != null)
{
Debug.WriteLine($"######## Id Scan OcrData => {JsonConvert.SerializeObject(result.OcrData)}.");
Debug.WriteLine($"######## Id Scan ExtendedOcrData {result.ExtendedOcrData}.");
}
if (result.FrontIdStatus == IdValidationResult.ValidationStatus.Ok &&
result.BackIdStatus == IdValidationResult.ValidationStatus.Ok)
{
Debug.WriteLine("######## Id Scan Successful!");
}
else
{
Debug.WriteLine($"######## Id Scan Unsuccessful! due to: FrontIdStatus ({result.FrontIdStatus}) & BackIdStatus({result.BackIdStatus})");
}
}
else if (result.Result == ResultCode.Error)
{
Debug.WriteLine($"######## Id Scan failed with Error => {result.ErrorMessage}.");
// TODO - Manage module error
// TODO - Save current module executed with failure
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
}
}
}
private void ProcessSelfieScanCallback(SelfieScanResult result)
{
if (result != null)
{
if (result.Result == ResultCode.Success)
{
Debug.WriteLine("######## Selfie Scan Completed!");
Debug.WriteLine($"######## Result => {result}");
// TODO - Manage module success completion
// TODO - Save/store relevant information for future use in the app
// TODO - Save current module executed succesfully
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
Debug.WriteLine($"####### Selfie Scan ScanStatus => {result.ScanStatus}.");
if (result.ScanStatus == SelfieScanResult.Status.Ok)
{
Debug.WriteLine("######## Selfie Scan Successful!");
Debug.WriteLine($"####### Selfie Image in Base64 => {result.SelfieImage}.");
Debug.WriteLine($"####### Selfie Scan FaceMatched => {(result.FaceMatched.HasValue ? result.FaceMatched.Value ? "Yes" : "No" : "Null")}.");
Debug.WriteLine($"####### Selfie Scan SpoofAttempt => {(result.SpoofAttempt.HasValue ? result.SpoofAttempt.Value ? "Yes" : "No" : "Null")}.");
}
else
{
Debug.WriteLine($"######## Selfie Scan Unsuccessful! due to: => {result.ScanStatus}");
}
}
else if (result.Result == ResultCode.Error)
{
Debug.WriteLine($"######## Selfie Scan failed with Error => {result.ErrorMessage}.");
// TODO - Manage module error
// TODO - Save current module executed with failure
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
}
}
}
private void ProcessFaceMatchCallback(FaceMatchResult result) {
if (result != null){
if (result.Result == ResultCode.Success){
Debug.WriteLine("######## Face Match Completed!");
Debug.WriteLine($"######## Result => {result}");
// TODO - Manage module success completion
// TODO - Save/store relevant information for future use in the app
// TODO - Save current module executed succesfully
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
Debug.WriteLine($"######## Face Mached: {(result.FaceMatched.HasValue ? result.FaceMatched.Value ? "Yes" : "No" : "Null")}");
if (result.FaceMatched == true)
{
if(result.ExistingUser == true)
{
Debug.WriteLine($"######## User found in this session: {result.ExistingInterviewId}");
if (result.NameMatched == true)
{
// TODO - EVERYTHING OK - This is just a new user onboarding attempt
}
else
{
// TODO - WARNING - Manage fraud attempt
}
}
else
{
// TODO - EVERYTHING OK - This is just a completly new user
}
}
else
{
// TODO - WARNING - Manage fraud attempt
}
}
else if (result.Result == ResultCode.Error)
{
Debug.WriteLine($"######## Face Match failed with Error => {result.ErrorMessage}.");
// TODO - Manage module error
// TODO - Save current module executed with failure
// TODO - Apply specific business logic
// TODO - Save flag to be used to control de general onboarding flow
}
}
}
// Not possible to do it in Cordova for now
// Not possible to do it in Cordova for now
Step 5: Execute the Onboarding
Once the SDK is initialized, flow is configured, session is created, and callbacks are implemented, then it is ready for the user to start the flow by calling the startOnboarding
function.
private void startStraightforwardOnboarding(Activity activity) {
setIncodeCommonConfig();
SessionConfig sessionConfig = getSimpleSession();
FlowConfig flowConfig = getStraightforwardFlowConfig();
IncodeWelcome.OnboardingListener onboardingListener = getStraightforwardOnboardingListener();
IncodeWelcome.getInstance().startOnboarding(activity, sessionConfig, flowConfig, onboardingListener);
}
func startStraightforwardOnboarding() {
setIncodeCommonConfig()
let sessionConfig = createSessionConfiguration()
let flowConfig = createFlowConfiguration()
IncdOnboardingManager.shared.presentingViewController = self
IncdOnboardingManager.shared.startOnboarding(sessionConfig: sessionConfig, flowConfig: flowConfig, delegate: self)
}
function startStraightforwardOnboarding(){
let sessionConfig = getSimpleSession();
let flowConfig = getStraightforwardFlowConfig();
IncodeSdk.startOnboarding({
flowConfig: flowConfig,
sessionConfig: sessionConfig,
})
.then((result) => {
fetchUserScores();
})
.catch((e) => {
// TODO - Manage Onboarding error
});
}
void startStraightforwardOnboarding(){
var sessionConfig = getSimpleSession();
var flowConfig = getStraightforwardFlowConfig();
IncodeOnboardingSdk.startOnboarding(
sessionConfig: sessionConfig,
flowConfig: flowConfig,
onSuccess: onSuccessCallback,
onError: onErrorCallback,
onUserCancelled: onUserCancelledCallback,
onIdFrontCompleted: onIdFrontCompletedCallback,
onIdBackCompleted: onIdBackCompletedCallback,
onIdProcessed: onIdProcessedCallback,
onSelfieScanCompleted: onSelfieScanCompletedCallback,
onFaceMatchCompleted: onFaceMatchCompletedCallback
);
}
IncodeOnboarding.Current.StartOnboarding(config);
document.getElementById("element").addEventListener("click", incodeSDKInitialize);
this.incodeSDKInitialize()
Step 6: Process Results
Last but not least, when the user completes the flow, fetch the results and implement the business logic as needed to JUST redirect the user to the screen you need.
They recommended place to apply the business logic to evaluate the onboarding status and gran access to the product you offer is in the backend, please review this explanation of fetch scores in a deep to achive that.
private void fetchUserScores(String interviewId) {
IncodeWelcome.getInstance().getUserScore(FAST, interviewId, new GetUserScoreListener() {
@Override
public void onUserScoreFetched(UserScoreResult result) {
Timber.d("onUserScoreFetched: %s", result);
validateResultWithBusinessLogic(result);
}
@Override
public void onUserCancelled() {
Timber.d("getUserScore onUserCancelled");
}
@Override
public void onError(Throwable error) {
Timber.d("getUserScore onError: %s", error);
}
});
}
private void validateResultWithBusinessLogic(UserScoreResult result) {
// TODO - Apply business rules to check the scores of the session
}
func fetchUserScore() {
IncdOnboardingManager.shared.getUserScore(userScoreFetchMode: UserScoreFetchMode.fast, interviewId: interviewId ,completion: {
userScore in
if(userScore.error != nil) {
validateResultWithBusinessLogic()
}
else {
// TODO - Manage fetch user score error
}
})
}
func validateResultWithBusinessLogic(userScore:UserScore) {
// TODO - Apply business rules to check the scores of the session
}
function fetchUserScores(interviewId) {
IncodeSdk.getUserScore({ mode: 'fast' })
.then((result) => {
validateResultWithBusinessLogic(result);
})
.catch((e) => {
// TODO - Manage getting User Score error
});
}
function validateResultWithBusinessLogic(result){
// TODO - Apply business rules to check the scores of the session
}
void fetchUserScores() {
IncodeOnboardingSdk.getUserScore(
onSuccess: (result) {
validateResultWithBusinessLogic(result);
},
onError: (error) {
// TODO - Manage getting User Score error
}
);
}
void validateResultWithBusinessLogic(result){
}
//To fetch scores or results once onboarding modules are done.
function getUserScore(){
cordova.exec(function(winParam) {
console.log("showUserScore Success: "+winParam);
myObj = JSON.stringify(winParam);
console.log("Score : "+myObj);
deleteLocalUserData();
}, function(err) {
console.log("Error: "+ err);
callbackError('Nothing to echo.' +err);
}, "Cplugin", "getUserScore", ["fast"]);
}
//To finish the session below code is mandatory after all sections or modules are completed successfully. This should be called only once when all the sections are done.
function finishOnboarding(){
cordova.exec(function(winParam) {
console.log("finishOnboarding Success: "+winParam);
getUserScore();
}, function(err) {
console.log("Error: "+ err);
callbackError('Nothing to echo.' +err);
}, "Cplugin", "finishOnboarding", []);
}
//Make sure to delete local cache data once all all the above steps are over.
function deleteLocalUserData(){
cordova.exec(function(winParam) {
console.log("deleteLocalUserData Success: "+winParam);
}, function(err) {
console.log("Error: "+ err);
}, "Cplugin", "deleteUserLocalData", []);
}
//To finish the session below code is mandatory after all sections or modules are completed successfully. This should be called only once when all the sections are done.
finishOnboarding(): void {
console.log("finishOnboarding");
cordova.exec((winParam: any) => {
console.log("finishOnboarding Success: ", winParam);
this.getUserScore();
}, (err: string) => {
console.log("Error: ", err);
this.callbackError(err);
}, "Cplugin", "finishOnboarding", []);
}
//To fetch scores or results once onboarding modules are done.
getUserScore(): void {
console.log("getUserScore");
cordova.exec((winParam: any) => {
console.log("getUserScore Success: ", winParam);
this.deleteLocalUserData();
}, (err: string) => {
console.log("Error: ", err);
this.callbackError(err);
}, "Cplugin", "getUserScore", ["fast"]);
}
//Make sure to delete local cache data once all all the above steps are over.
deleteLocalUserData(): void {
console.log("deleteUserLocalData");
cordova.exec((winParam: any) => {
console.log("deleteLocalUserData Success: ", winParam);
this.navigateTo();
}, (err: string) => {
console.log("Error: ", err);
}, "Cplugin", "deleteUserLocalData", []);
}
Note: It's very important to understand that you can manage your App UI navigation or API calls in TODO section (validateResultWithBusinessLogic method), but by safety and best practices, the business rules must be applied in your backend, for example user's onboarding approve, change status, etc.
Working example project
Once you setup your environment to integrate Incode and once you reaf the explanation about the general steps to integrate the SDK into the different availble flavors, we have a working examples on each platform that can be use as a playground to test the Incode modules available
Updated 6 months ago