# Prerequisites

It is first required to Setup Environment install the SDK into the project follow the details outlined in the [Setup Environment](https://developer.incode.com/docs/android-native)

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.

# Step 1: Initialize the Incode SDK

## Fast way to initialize the SDK

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.

AndroidiOSReact NativeFlutter

```java
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);
}
```

```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
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);
      });
  };
```

```text
void IncodeSDKInitialize(API_URL,API_KEY) {
    IncodeOnboardingSdk.init(
        apiKey: API_KEY,
        apiUrl: API_URL,
        testMode: false,
        onError: (String error) {
          print('Incode SDK init failed: $error');
        },
        onSuccess: () {
          print('Incode SDK init success:');
        },
    );
  }
```

## 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 backend know how to manage the request using only the token of the session. You need to initialize the SDK in this way:

AndroidiOSReact NativeFlutter

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

IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
```

```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
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);
      });
  };
```

```text
void IncodeSDKInitialize(API_URL, API_KEY) {
    IncodeOnboardingSdk.init(
      apiUrl: API_URL + "/0/",
      onError: (String error) {
        print('Incode SDK init failed: $error');
      },
      onSuccess: () {
        onStartOnboarding();
      },
    );
}
```

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

## Fast way session creation

AndroidiOSReact NativeFlutter

```java
private SessionConfig getSimpleFlowSession() {
    SessionConfig sessionConfig = new SessionConfig.Builder()
            .setRegionIsoCode("ALL")
            .setConfigurationId(Constants.CONFIGURATION_ID)
            .build();

return sessionConfig;
}
```

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

```javascript
function getSimpleWorkflowSession() {
    let sessionConfig = {
      region: 'ALL',
      configurationId: WORKFLOW_ID,
    };

return sessionConfig;
}
```

```text
OnboardingSessionConfiguration getSimpleFlowSession() {
    IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
    OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(configurationId: CONFIGURATION_ID);
    return sessionConfig;
}
```

## 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:

AndroidiOSReact NativeFlutter

```java
private SessionConfig getSimpleFlowSession() {
    SessionConfig sessionConfig = new SessionConfig.Builder()
            .setRegionIsoCode("ALL")
            .setExternalToken(SESSION_TOKEN_FROM_BACKEND)
            .build();

return sessionConfig;
}
```

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

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

return sessionConfig;
}
```

```text
OnboardingSessionConfiguration getSimpleFlowSession() {
    IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true);
    OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(token: SESSION_TOKEN_FROM_BACKEND);
    return sessionConfig;
}
```

# Step 3: Implement the callbacks

During the user's journey to the flow, various callbacks are executed. Custom business logic can be added in these callbacks, but showing a custom screen in between steps is not supported.

AndroidiOSReact NativeFlutter

```java
private IncodeWelcome.OnboardingListener getFlowOnboardingListener() {
        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;
    }
```

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

fetchUserScores()
    }

func onError(_ error: IncdFlowError) {
        print("onError, result: \(error)")
    }

func userCancelledSession() {
        print("userCancelledSession")
    }
}
```

```javascript
// Register listeners for relevant events when the component gets mounted
React.useEffect(() => {
  const unsubscribers = setupListeners(); // defined below

// return a function unregistering all your listeners (called when component is unmounted)
  return () => {
    unsubscribers.forEach((unsubscriber) => unsubscriber());
  };
}, []);

const setupListeners = () => {
  // returns a callback to unregister your listener, e.g. when your screen is getting unmounted
  IncodeSdk.onSessionCreated((session) => {
      console.log('Onboarding session created, interviewId: ' + session.interviewId);
    })

const complete = IncodeSdk.onStepCompleted;
  return [
    complete({
      module: 'IdScanFront',
      listener: (e) => {
        console.log('ID scan front:', e.result);
      },
    }),
    complete({
      module: 'IdScanBack',
      listener: (e) => {
        console.log('ID scan back: ', e.result);
      },
    }),
    complete({
      module: 'ProcessId',
      listener: (e) => {
        console.log('ProcessId result: ', e.result.extendedOcrData);
      },
    }),
    complete({
      module: 'SelfieScan',
      listener: (e) => {
        console.log('Selfie scan complete', e.result);
      },
    }),
    complete({
      module: 'FaceMatch',
      listener: (e) => {
        console.log('Face match complete', e.result);
      },
    }),
  ];
};
```

```text
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);
}
```

# Step 4 - Execute the Flow

AndroidiOSReact NativeFlutter

```java
private void startFlow() {
  setIncodeCommonConfig();
  SessionConfig sessionConfig = getSimpleFlowSession();
  IncodeWelcome.OnboardingListener onboardingListener = getFlowOnboardingListener();
  IncodeWelcome.getInstance().startFlow(activity, sessionConfig, onboardingListener);
}
```

```swift
func startFlow() {
  setIncodeCommonConfig()
  let sessionConfig = getSimpleFlowSession();
  IncdOnboardingManager.shared.presentingViewController = self
  IncdOnboardingManager.shared.startFlow(sessionConfig: sessionConfig, delegate: self)
}
```

```javascript
function startWorkflow(){
    let sessionConfig = getSimpleFlowSession();

IncodeSdk.startFlow({
      sessionConfig: sessionConfig,
    })
      .then((result) => {
        fetchUserScores();
      })
      .catch((e) => {
        // TODO - Manage Onboarding error
      });
  }
```

```text
void startFlow(){
    var sessionConfig = getSimpleFlowSession();

IncodeOnboardingSdk.startFlow(
      sessionConfig: sessionConfig,
      onSuccess: onSuccessCallback,
      onError: onErrorCallback,
      onUserCancelled: onUserCancelledCallback,
      onIdFrontCompleted: onIdFrontCompletedCallback,
      onIdBackCompleted: onIdBackCompletedCallback,
      onIdProcessed: onIdProcessedCallback,
      onSelfieScanCompleted: onSelfieScanCompletedCallback,
      onFaceMatchCompleted: onFaceMatchCompletedCallback,
    );
}
```

# Step 5: 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 grant access to the product you offer is in the backend, please review this explanation of [fetch scores](https://developer.incode.com/docs/fetch-scores) in depth to achieve that.

AndroidiOSReact NativeFlutter

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

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

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

```text
void fetchUserScores() {
  IncodeOnboardingSdk.getUserScore(
    onSuccess: (result) {
      validateResultWithBusinessLogic(result);
    },
    onError: (error) {
      // TODO - Manage getting User Score error
    }
  );
}

void validateResultWithBusinessLogic(result){
}
```
