> For the complete documentation index, see [llms.txt](https://docs.facephi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facephi.com/docs.facephi-en/sdks/sdk-mobile/android-sdk/ajustes-avanzados.md).

# Advanced settings

## Introduction <a href="#id-1-introduccion" id="id-1-introduccion"></a>

This section expands on the general information about the SDK launch.

***

## Advanced information about the SDK launch <a href="#id-2-informacion-avanzada-del-lanzamiento-del-sdk" id="id-2-informacion-avanzada-del-lanzamiento-del-sdk"></a>

This section expands the information in the "Simplified Launch of the SDK" section.

### Add private repository <a href="#id-21-anadir-repositorio-privado" id="id-21-anadir-repositorio-privado"></a>

For security and maintenance reasons, the new components of the ***SDKMobile*** are stored in private repositories that require specific credentials to access them. You must obtain those credentials through the *support team* from **Facephi**.

Once the credentials have been obtained, the following code snippet must be included to configure the Maven repository in the **Gradle** of your project, or in the file **settings.gradle** for it. It is recommended to include it after *mavenCentral()*

```kotlin
maven {
    Properties props = new Properties()
    def propsFile = new File('local.properties')
    if(propsFile.exists()){
        props.load(new FileInputStream(propsFile))
    }
    name="external"
    url = uri("https://facephicorp.jfrog.io/artifactory/maven-pro-fphi")
    credentials {
        username = props["artifactory.user"] ?: System.getenv("USERNAME_ARTIFACTORY")
        password = props["artifactory.token"] ?: System.getenv("TOKEN_ARTIFACTORY")
    }
}
```

For the project to correctly retrieve the dependencies, the credentials (Username and Token) must be correctly configured

There are several ways to configure the repository access credentials:

* As environment variables with the following names. For example:

  ```
  export USERNAME_ARTIFACTORY=YOUR_CREDENTIALS_USERNAME
  export TOKEN_ARTIFACTORY=YOUR_CREDENTIALS_TOKEN
  ```

  **If the dependencies are not recognized when syncing**, they must be included through environment variables in the file:

`~/.zshrc`

* Included in the file *local.properties* with the following structure:

  ```
  artifactory.user=YOUR_CREDENTIALS_USERNAME
  artifactory.token=YOUR_CREDENTIALS_TOKEN
  ```

### SDK Initialization <a href="#id-22-inicializacion-del-sdk" id="id-22-inicializacion-del-sdk"></a>

**You should avoid initializing a controller that will not be used**.

The SDK works through a main controller (SDKController) that must be initialized correctly in order to use the rest of the functionality. The steps to follow in the initialization are:

1. Include the Application object through the SdkApplication class.
2. Decide whether the license will be included through a *String* or with a *remote licensing service* (see **section 3.1**).
3. The controller *TrackingController* if you want to connect to the platform.

The **point 3** is optional, and would require using the Tracking component (more information about this module in its own documentation).

An example of initialization without *TrackingController* would be the following:

```kotlin
val sdkConfig = SdkConfigurationData(
    sdkApplication = SdkApplication(application),
    licensing = LicensingOffline("LICENSE")
)

val result = SDKController.initSdk(sdkConfig)

when (result) {
  is SdkResult.Success -> Napier.d("APP: INIT SDK: OK")
  is SdkResult.Error -> Napier.d(
          "APP: INIT SDK: KO - ${result.error.name}"
        )
}
```

An example of initialization with *TrackingController* would be the following:

```kotlin
val sdkConfig = SdkConfigurationData(
    sdkApplication = SdkApplication(application),
    licensing = LicensingOffline("LICENSE"),
    trackingController = TrackingController(),
)

val result = SDKController.initSdk(sdkConfig)

when (result) {
  is SdkResult.Success -> Napier.d("APP: INIT SDK: OK")
  is SdkResult.Error -> Napier.d(
          "APP: INIT SDK: KO - ${result.error.name}"
        )
}
```

#### **License injection**

As mentioned previously, there are currently two ways to inject the license:

**a. Obtaining the license through a service**

Through a service that will simply require a URL and an API-KEY as an identifier. This would avoid problems when handling the license, as well as the constant replacement of those licenses when a problem arises with it (corruption or improper modification, license expiration...)

Example implementation in Kotlin:

```kotlin
val sdkConfig = SdkConfigurationData(
    sdkApplication = SdkApplication(application),
    licensing = LicensingOnline(EnvironmentLicensingData(
            apiKey = "...")
      )),
)

val result = SDKController.initSdk(sdkConfig)

when (result) {
  is SdkResult.Success -> Napier.d("APP: INIT SDK: OK")
  is SdkResult.Error -> Napier.d(
          "APP: INIT SDK: KO - ${result.error.name}"
        )
}
```

Example implementation in Java:

```kotlin
SDKController.INSTANCE.initSdk(
    new SdkApplication(activity.getApplication()),
    new LicensingOnline(new EnvironmentLicensingData(
      apiKey = "...")),
    sdkResult ->
    {
      if (sdkResult instanceof SdkResult.Success) {
        Napier.d("APP: INIT SDK: OK")
      } else if (sdkResult instanceof SdkResult.Error) {
        Napier.d("APP: INIT SDK: KO - ${it.error}")
      }
    }
  );
```

**b. Injecting the license as a String**

The license can be assigned directly as a String, as follows:

Example implementation in Kotlin:

```kotlin
val sdkConfig = SdkConfigurationData(
    sdkApplication = SdkApplication(application),
    licensing = LicensingOffline("LICENSE"),
)

val result = SDKController.initSdk(sdkConfig)

when (result) {
  is SdkResult.Success -> Napier.d("APP: INIT SDK: OK")
  is SdkResult.Error -> Napier.d(
          "APP: INIT SDK: KO - ${result.error.name}"
        )
}
```

Example implementation in Java:

```kotlin
SDKController.INSTANCE.initSdk(
  new SdkApplication(activity.getApplication()),
  new LicensingOffline("LICENSE"),
  sdkResult ->
  {
    if (sdkResult instanceof SdkResult.Success) {
      Timber.d("APP: INIT SDK: OK")
    } else if (sdkResult instanceof SdkResult.Error) {
      Timber.d("APP: INIT SDK: KO - ${it.error}")
    }
  }
);
```

#### **Error handling**

In the error part, we will have the SdkError class.

List of errors:

* EMPTY\_LICENSE: Empty license
* INIT\_AI\_MODELS(error: String): Error obtained in the model download service
* INIT\_FLOW (error: String): Error obtained in the flow download service
* LICENSE\_CHECKER\_ERROR (error: String): Error obtained when verifying whether the license is correct
* LICENSING\_ERROR (error: String): Error obtained in the license download service
* NETWORK\_CONNECTION\_ERROR: Internet connection error
* TRACKING\_ERROR (error: String): Error obtained when starting the Tracking controller

***

## Start new operation <a href="#id-3-iniciar-nueva-operacion" id="id-3-iniciar-nueva-operacion"></a>

Whenever you want to start the flow of a new operation (examples of operations would be: *onboarding, authentication, videoCall*,...) it is essential to indicate to the **SDKController** that it is about to begin, and thus the SDK will know that the next calls to **Components** (also called **Steps**) will be part of that operation.

When starting a process or flow, **always** the method call must be made **newOperation**

This method has the following input parameters:

1. **operationType**: Indicates whether an ONBOARDING or AUTHENTICATION process will be performed.
2. **customerId**: Unique user ID, if available (controlled at application level)
   1. This parameter will appear reflected for each operation in the platform.
3. **steps**: List of operation steps if they have been defined beforehand
4. **enableTracking**: Allows enabling or disabling the sending of tracking events for this operation. If not specified, it is considered `true`.

There are 2 ways to perform this operation start, depending on whether **the steps are known** that will make up the registration or authentication process flow (in case the components are executed sequentially and always in the same way) or, otherwise, if the flow **is not defined** and is unknown (for example, the end customer is the one who decides the execution order of the components).

* Flow **known** (the operation will appear *tracked* in the platform with all the steps in the list).

  Example Kotlin implementation:

```kotlin
val result = SDKController.newOperation(
        operationType = OperationType.ONBOARDING,
        customerId = "customer_id",
        steps = listOf(Step.SELPHI_COMPONENT, Step.SELPHID_COMPONENT),
        enableTracking = true)
when (result) {
    is SdkResult.Success -> {
        Timber.d("APP: NEW OPERATION OK")
        Timber.d("Session ID: ${result.data.sessionId}")
        Timber.d("Operation ID: ${result.data.operationId}")
    }
    is SdkResult.Error -> {
        Timber.d("APP: NEW OPERATION ERROR: ${result.error.name}")
    }
}
```

Example Java implementation:

```kotlin
 SDKController.INSTANCE.newOperation(
        OperationType.ONBOARDING,
        "customer_id",
        [Step.SELPHI_COMPONENT, Step.SELPHID_COMPONENT]
        ){
          if (sdkResult instanceof SdkResult.Success) {
            Napier.d("APP: NEW OPERATION: OK")
          } else if (sdkResult instanceof SdkResult.Error) {
            Napier.d("APP: NEW OPERATION: KO - ${it.error}")
          }
        }
  );
```

* Flow **unknown** (the operation will appear *tracked* in the platform with ellipses). Example Kotlin implementation:

```kotlin
val result = SDKController.newOperation(
        operationType = OperationType.ONBOARDING,
        customerId = "customer_id",
        enableTracking = true)
when (result) {
    is SdkResult.Success -> {
        Timber.d("APP: NEW OPERATION OK")
    }
    is SdkResult.Error -> {
        Timber.d("APP: NEW OPERATION ERROR: ${result.error.name}")
    }
}
```

Example Java implementation:

```kotlin
 SDKController.INSTANCE.newOperation(
        OperationType.ONBOARDING,
        "customer_id"
        ){
          if (sdkResult instanceof SdkResult.Success) {
            Napier.d("APP: NEW OPERATION: OK")
          } else if (sdkResult instanceof SdkResult.Error) {
            Napier.d("APP: NEW OPERATION: KO - ${it.error}")
          }
        }
  );
```

`sdkResult` → Contains in `data` the information about the created operation.

When the result is correct, `data` is a `OperationResult` with:

| Field         | Description                                                   |
| ------------- | ------------------------------------------------------------- |
| `sessionId`   | Identifier of the session created or retrieved by the SDK.    |
| `operationId` | Identifier of the active operation.                           |
| `type`        | Type of operation started (`ONBOARDING` or `AUTHENTICATION`). |
| `customerId`  | User identifier associated with the operation.                |

**Once the operation has been created** the SDK components associated with this operation can be executed. Consult the specific documentation for each component to learn how to do it.

### **Existing operation types** <a href="#id-31-tipos-de-operacion-existentes" id="id-31-tipos-de-operacion-existentes"></a>

Currently, the following operations exist, during which certain **Components (STEPS).**

The following table shows the relationship between *operations* and *steps*:

| **Operation (OperationType)** | **Component (Step)**                           | Description                                                                                                                         |
| ----------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| ONBOARDING                    | <p>SELPHI\_COMPONENT<br>SELPHID\_COMPONENT</p> | <p>- Facial validation of a selfie against the face on a document<br>- Extraction of the document's OCR<br>- Liveness detection</p> |
| AUTHENTICATION                | SELPHI\_COMPONENT                              | <p>- Facial validation using templates<br>- Liveness detection</p>                                                                  |

This list will be expanded in future SDK updates, as new components and use cases appear.

{% hint style="info" %}
If the creation of a new operation returns an error of type **INTERNAL\_ERROR** it is mainly due to a **security**. To investigate the cause, it is possible to retrieve the Token associated with the error, which provides additional information for analysis.

```
if (result.error is SdkError.INTERNAL_ERROR){
    val token = (result.error as SdkError.INTERNAL_ERROR).error
}
```

{% endhint %}

***

## Security <a href="#id-24-lanzamiento-de-los-componentes" id="id-24-lanzamiento-de-los-componentes"></a>

The Android SDK includes a security system designed to detect and block potentially untrusted environments or those that may indicate attack attempts.<br>

This mechanism is enabled by default, allows identifying situations that could compromise security, and prevents the SDK from running in contexts that are not considered secure:

```
SDKController.securityMode(enable: Boolean) 
```

***

## Component launch <a href="#id-4-lanzamiento-de-componentes" id="id-4-lanzamiento-de-componentes"></a>

The SDK functionality is divided into different components with specific controllers. These controllers will be "launched" from the general controller.

Once the **new operation** (**section 3**), the different SDK controllers can be launched. To consult this information, you must access the **documentation for each of the specific components**.

Example Kotlin launch:

```kotlin
val result = SDKController.launch(ExampleController(ConfigurationData()))
when (result) {
    is SdkResult.Success -> {
        //Result OK
        result.data
    }
    is SdkResult.Error -> {
        //Result KO
        result.error.name
    }
}
```

Example Java launch:

```kotlin
SDKController.INSTANCE.launch(
    new ExampleController(new ConfigurationData()) {
        if (sdkResult instanceof SdkResult.Success) {
            //Result OK
            it.data
          } else if (sdkResult instanceof SdkResult.Error) {
            //Result KO
            it.error.name
          }
    }
)
```

### Options for component launch <a href="#id-41-opciones-para-el-lanzamiento-del-componente" id="id-41-opciones-para-el-lanzamiento-del-componente"></a>

Once the SDK has been started and a new operation has been created, the component can be launched. There are two ways to launch the component:

* **\[WITH TRACKING]** This call allows the component functionality to be launched normally, but internal events will be tracked to the server of *tracking*:

```
val response = SDKController.launch(
    ExampleController(SConfigurationData(...))
)
when (response) {
    is SdkResult.Error -> Napier.d("ERROR - ${response.error.name}")
    is SdkResult.Success -> response.data
}
```

* **\[WITHOUT TRACKING]** This call allows the component functionality to be launched normally, but **nothing will be tracked** to the server of *tracking*:

```
val response = SDKController.launchMethod(
    ExampleController(ConfigurationData(...))
)
when (response) {
    is SdkResult.Error -> Napier.d("ERROR - ${response.error.name}")
    is SdkResult.Success -> response.data
}
```

The method **launch** must be used **by default**. This method allows using ***tracking*** it if its component is enabled, and it will not be used when it is disabled (or the component is not installed).

On the other hand, the method **launchMethod** covers a special case in which the integrator has Tracking installed and enabled, but in a specific flow within the application does not want to track information. In that case, this method is used to prevent that information from being sent to the platform.

***

## Result return <a href="#id-5-retorno-de-resultado" id="id-5-retorno-de-resultado"></a>

The result of each component will be returned through the SDK, always maintaining the same structure through the class ***SdkResult*** whose class is a Sealed Class that can have 2 possible states:

* SdkResult.Success: Indicates that the operation has completed correctly and inside it contains:
  * ***data:*** Contains the data type needed according to the process/component launched.
* SdkResult.Error
  * ***error:*** Contains the error type needed according to the process/component launched.

The documentation for each specific component will break down the different fields that this object can return

Usage example:

```kotlin
when (result) {
    is SdkResult.Success -> {
        Napier.d("Selphi: OK")
        // SelphiResult:
        // result.data.bestImage
    }

    is SdkResult.Error -> Napier.d("Selphi: KO - ${result.error.name}")
}
```

***

## Auxiliary controllers <a href="#id-6-controladores-auxiliares" id="id-6-controladores-auxiliares"></a>

This section includes other controllers and auxiliary operations, some of them optional, and which may be necessary for the proper completion of the Flow.

These fields are necessary for communication with the **Facephi**, in case you want to perform any **verification** and want to perform the *tracking* of a specific operation.

### Obtaining the OperationId <a href="#id-61-obtencion-del-operationid" id="id-61-obtencion-del-operationid"></a>

```
val result = SDKController.launch(GetOperationIdController())
Napier.d("Operation ID ${result}")
```

### Obtaining the OperationType <a href="#id-62-obtencion-del-operationtype" id="id-62-obtencion-del-operationtype"></a>

```
val result = SDKController.launch(GetOperationTypeController())
Napier.d("Operation type ${result}")
```

### Obtaining the SessionId <a href="#id-63-obtencion-del-sessionid" id="id-63-obtencion-del-sessionid"></a>

```
val result = SDKController.launch(GetSessionIdController())
Napier.d("Session ID ${result}")
```

### Obtaining the CustomerID <a href="#id-64-obtencion-del-customerid" id="id-64-obtencion-del-customerid"></a>

```
val result = SDKController.launch(GetCustomerIdController())
Napier.d("Customer ID ${result}")
```

### Assigning the CustomerID <a href="#id-65-asignacion-del-customerid" id="id-65-asignacion-del-customerid"></a>

```
SDKController.launch(CustomerIdController("CustomerId"))
```

***

## Debug options and error handling <a href="#id-7-opciones-de-depuracion-y-control-de-errores" id="id-7-opciones-de-depuracion-y-control-de-errores"></a>

There are certain options in the SDK that allow for increased debug logs so you can verify that everything is working correctly.

### Error handling in Tracking connections with the platform <a href="#id-71-control-de-errores-en-las-conexiones-de-tracking-con-la-plataforma" id="id-71-control-de-errores-en-las-conexiones-de-tracking-con-la-plataforma"></a>

Once the SDK has been started correctly, certain adjustments can be applied to obtain more information about possible tracking errors; monitoring can be performed through this controller launch:

```kotlin
SDKController.launch(TrackingErrorController {
    Napier.d("Tracking Error: ${it.name}")
})
```

### Enabling general debug logs <a href="#id-72-activacion-de-logs-de-depuracion-general" id="id-72-activacion-de-logs-de-depuracion-general"></a>

```kotlin
 if (BuildConfig.DEBUG) {
  SDKController.enableDebugMode()
 }
```

***

## Tracking and Analysis of Events in the Application <a href="#id-8-seguimiento-y-analisis-de-eventos-en-la-aplicacion" id="id-8-seguimiento-y-analisis-de-eventos-en-la-aplicacion"></a>

The event functionality allows key interactions within the application, such as screen changes and user actions, to be recorded and interpreted, facilitating real-time behavior analysis.

Each event is sent with a timestamp, type, and specific detail, providing structured tracking and optimizing the user experience with precise and actionable data.

```kotlin
 SDKController.getAnalyticsEvents { time, componentName, eventType, info ->
            Log.i { "EVENTS", "*** $time - ${componentName.name} -" +
                " ${eventType.name} -  ${info ?: ""} " }
        }
```
