# Prerequisites

You must first set up your mobile environment. To do so, install the SDK into the project following the instructions at [Setup Environment](https://developer.incode.com/docs/android-native). 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

```java
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

```swift
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

```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

```javascript
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

```csharp
// 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

```java
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

```swift
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

```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

```javascript
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](https://developer.incode.com/getting-started-with-incode-onboarding).

### Android

```java
private SessionConfig getSimpleSession() {
    SessionConfig sessionConfig = new SessionConfig.Builder()
            .setConfigurationId(Constants.CONFIGURATION_ID)
            .build();

return sessionConfig;
}
```

### iOS

```swift
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
  return IncdOnboardingSessionConfiguration(regionCode: "ALL",
                                            configurationId: "PASTE__HERE_CONFIGURATION_ID")
}
```

### JavaScript

```javascript
function getSimpleSession() {
    let sessionConfig: {
      region: 'ALL',
      configurationId: CONFIGURATION_ID,
    };

return sessionConfig;
}
```

### Flutter

```javascript
OnboardingSessionConfiguration getSimpleSession() {
  // Common configs
  IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);

// Session config
  OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(configurationId: CONFIGURATION_ID);

return sessionConfig;
}
```

### Xamarin

```javascript
// Not possible to do it in Xamarin for now
```

### JavaScript

```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

```java
private SessionConfig getSimpleSession() {
    SessionConfig sessionConfig = new SessionConfig.Builder()
            .setExternalToken(SESSION_TOKEN_FROM_BACKEND)
            .build();

return sessionConfig;
}
```

### iOS

```swift
func createSessionConfiguration() -> IncdOnboardingSessionConfiguration {
  return IncdOnboardingSessionConfiguration(regionCode: "ALL",
                                            token: SESSION_TOKEN_FROM_BACKEND)
}
```

### JavaScript

```javascript
function getSimpleSession() {
    let sessionConfig: {
      region: 'ALL',
      token: SESSION_TOKEN_FROM_BACKEND,
    };

return sessionConfig;
}
```

### JavaScript

```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

```java
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

```swift
func createFlowConfiguration() -> IncdOnboardingFlowConfiguration {
  let flowConfig = IncdOnboardingFlowConfiguration(waitForTutorials: true)
  flowConfig.addIdScan()
  flowConfig.addProcessId()
  flowConfig.addSelfieScan()
  flowConfig.addFaceMatch()
  return flowConfig
}
```

### JavaScript

```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

```javascript
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

```csharp
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

```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

```java
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

```swift
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

```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

```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

```csharp
private void ProcessIdScanCallback(IdValidationResult result) {
  if (result != null) {
    if (result.Result == ResultCode.Success) {
      Debug.WriteLine("######## Id Scan Completed!");
      Debug.WriteLine($
