Full SDK Integration
Instructions for a straightforward implementation of Incode Mobile Onboarding.
Prerequisites
You must first set up your mobile environment. To do so, install the SDK into the project following the instructions at Setup Environment. Remember:
- The minimum supported Android version is 23, which supports 98.4% of devices.
- The minimum supported iOS version is iOS 13, which supports 99.6% of devices.
High level
This diagram offers a high-level illustration of a straightforward integration. You view a full example of this integration in Github or you can view the recipe.
Step One: Initialize the Incode SDK
The Incode SDK must be initialized before it can be used. The initialization code is different depending on whether your sessions are created in the back end or in the front end.
The following example shows the initialization code for each platform when your sessions are not created in the back end.
public static void IncodeSDKInitialize(Application app) {
try {
new IncodeWelcome.Builder(app, Constants.API_URL, Constants.API_KEY)
.setLoggingEnabled(true)
.build();
// Initialization successful
} catch (Exception exception) {
// Initialization error
}
}
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"]);
}If you are creating the session in the back end, the API_URL needs to end with /0/. This lets the Incode back end know how to manage the request using only the token from the session. The following example shows the initialization code for each platform when your sessions are created in the back end.
public static void IncodeSDKInitialize(Application app) {
try {
new IncodeWelcome.Builder(app, Constants.API_URL+"/0/")
.setLoggingEnabled(true)
.build();
// Initialization successful
} catch (Exception exception) {
// Initialization error
}
}
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 nowfunction 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 Two: Create Session
A session must be created for data to be captured. You can choose whether sessions are created in the back end or front end. Either way, you need the Configuration ID, also known as the Incode Flow identifier or Flow ID, for your new sessions. If you don't know the Flow ID, open Dashboard > Flows, locate the Flow you want to reference, and click Copy Flow ID in the Actions column. If you have not yet configured the Flow you want to use, see the Getting Started Guide.
The following example shows the session creation code for each platform when your sessions are not created in the back end.
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.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]);
}If you are creating the session in the backend, you need to configure the session token to let the SDK save all the information captured during onboarding to that session. You also need to create a way to share that token from your backend to your frontend. This is usually done by an additional API that you need to create. Once the frontend has the token (SESSION_TOKEN_FROM_BACKEND), you pass it to the SDK.
The following example shows the code for each platform when you are creating sessions in the back end and need to pass the session token to the front end.
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.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 Three: Configure User Experience
The default onboarding experience is one in which:
- The user scans their ID
- The ID is processed
- A selfie is provided
- Face Match is performed
You can customize this user experience as needed. The following example shows the code for configuring the default experience for each platform.
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 Four: Implement Callbacks
During the user's journey through your onboarding flow, various callbacks are executed by Incode. You can add custom business logic in these callbacks if needed. However, showing a custom screen between steps is not supported.
The following example shows the code for implementing these callbacks in each platform.
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 nowStep Five: Execute Onboarding Session
Once the preceding steps are completed, mobile onboarding is ready for the user to start the flow by calling the startOnboarding function.
The following example shows the code for calling this function in each platform.
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 Six: Process Results
Once the user completes the onboarding flow, you can fetch the results. You can also implement only the business logic needed to redirect the user to the screen you need. Any business logic to evaluate onboarding status and grant access to your product should be in your backend. For more information on how to achieve this, see fetch scores.
The following example shows only the necessary code for each platform as described.
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", []);
}While it's possible to manage app navigation or API calls in the TODO section shown in this example using the
validateResultWithBusinessLogicmethod, we don't recommend it. Best practice is to apply business rules (such as for onboarding approval, change status, and so on) in your back end for both safety and security.
Working Example Project
Once you have set up your environment to integrate Incode and have read the preceding explanations for the various supported platforms, you may want to experiment a bit. We offer working examples on each platform. You can use these as a playground to test the available Incode modules.
Updated about 17 hours ago
