Full Standard SDK Integration
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.
Android
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);
}
iOS
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
}
JavaScript
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);
});
};
Flutter
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();
},
);
}
Xamarin
// 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);
}
}
}
If you are creating the session in the back end, the API token 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.
Android
public static void IncodeSDKInitialize(Application app) {
try {
new IncodeWelcome.Builder(app, Constants.API_URL + "/0/")
.setLoggingEnabled(true)
.build();
} catch (Exception exception) {
// Initialization error
}
}
IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
iOS
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()
}
}
JavaScript
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);
});
};
Flutter
void IncodeSDKInitialize(API_URL,API_KEY) {
IncodeOnboardingSdk.init(
apiUrl: API_URL + "/0/",
onError: (String error) {
print('Incode SDK init failed: $error');
},
onSuccess: () {
onStartOnboarding();
},
);
}
If you are creating the session in the back end, 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.
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.
Android
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.setConfigurationId(Constants.CONFIGURATION_ID)
.build();
return sessionConfig;
}
iOS
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
return IncdOnboardingSessionConfiguration(regionCode: "ALL",
configurationId: "PASTE__HERE_CONFIGURATION_ID")
}
JavaScript
function getSimpleSession() {
let sessionConfig: {
region: 'ALL',
configurationId: CONFIGURATION_ID,
};
return sessionConfig;
}
Flutter
OnboardingSessionConfiguration getSimpleSession() {
// Common configs
IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
// Session config
OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(configurationId: CONFIGURATION_ID);
return sessionConfig;
}
Xamarin
// Not possible to do it in Xamarin for now
JavaScript
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]);
}
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.
Android
private SessionConfig getSimpleSession() {
SessionConfig sessionConfig = new SessionConfig.Builder()
.setExternalToken(SESSION_TOKEN_FROM_BACKEND)
.build();
return sessionConfig;
}
iOS
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
return IncdOnboardingSessionConfiguration(regionCode: "ALL",
token: SESSION_TOKEN_FROM_BACKEND)
}
JavaScript
function getSimpleSession() {
let sessionConfig: {
region: 'ALL',
token: SESSION_TOKEN_FROM_BACKEND,
};
return sessionConfig;
}
JavaScript
OnboardingSessionConfiguration getSimpleSession() {
// Common configs
IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
// Session config
OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(token: SESSION_TOKEN_FROM_BACKEND);
return sessionConfig;
}
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.
Android
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;
}
iOS
func createFlowConfiguration() -> IncdOnboardingFlowConfiguration {
let flowConfig = IncdOnboardingFlowConfiguration(waitForTutorials: true)
flowConfig.addIdScan()
flowConfig.addProcessId()
flowConfig.addSelfieScan()
flowConfig.addFaceMatch()
return flowConfig
}
JavaScript
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;
}
Flutter
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;
}
Xamarin
config.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));
JavaScript
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"}]);
}
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.
Android
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;
}
iOS
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")
}
}
JavaScript
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());
};
}, []);
JavaScript
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);
}
JavaScript
private void ProcessIdScanCallback(IdValidationResult result) {
if (result != null) {
if (result.Result == ResultCode.Success) {
Debug.WriteLine("######## Id Scan Completed!");
Debug.WriteLine($