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

In this section, the general information about the SDK launch is expanded.

***

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

In this section, the information in the "Simplified Launch of the SDK" section will be expanded.

### 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 in order to access them. Those credentials must be obtained through the *support team* from **Facephi**.

Once the credentials have been obtained, the following code snippet should be included to configure the Maven repository in the **Gradle** of your project, or in the file **settings.gradle** of 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 retrieve the dependencies correctly, the credentials (Username and Token) must be configured correctly

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>

**A controller that will not be used should not be initialized**.

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 during 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 initialization example without *TrackingController* would be as follows:

```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 initialization example with *TrackingController* would be as follows:

```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 previously mentioned, 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 issues when handling the license, as well as the constant replacement of those licenses when any problem arises with it (malformation or improper modification, license expiration...)

Kotlin implementation example:

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

Java implementation example:

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

Kotlin implementation example:

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

Java implementation example:

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

On the error side, 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 a 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 going to begin, and thus the SDK will know that the next calls to **Components** (also called **Steps**) will form part of that operation.

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

This method has the following input parameters:

1. **operationType**: Indicates whether an ONBOARDING or AUTHENTICATION process is going to be performed.
2. **customerId**: Unique user ID if available (managed at application level)
   1. This parameter will be reflected for each operation on the platform.
3. **steps**: List of operation steps if they have been defined previously
4. **enableTracking**: Allows enabling or disabling the sending of tracking events for this operation. If not provided, 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 flow of the registration or authentication process (if the components are executed sequentially and always in the same way) or, otherwise, that 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* on the platform with all the steps from the list).

  Kotlin implementation example:

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

Java implementation example:

```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). Kotlin implementation example:

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

Java implementation example:

```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 `data` the information for the created operation.

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

| Field         | Description                                                |
| ------------- | ---------------------------------------------------------- |
| `sessionId`   | Identifier of the session created or retrieved by the SDK. |
| `operationId` | Identifier of the active operation.                        |
| `type`        | Started operation type (`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. Refer to 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) are used.**

Below is a table with 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 the 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 incorporates a security system designed to detect and block potentially untrusted environments or ones that may indicate attack attempts.<br>

This mechanism is enabled by default; it helps identify 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, access the **documentation for each of the specific components**.

Kotlin launch example:

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

Java launch example:

```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 launching the component <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 **no event 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 when its component is enabled, and it will not be used when it is disabled (or if the component is not installed).

By contrast, 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 finished correctly and contains:
  * ***data:*** Contains the data type needed according to the launched process/component.
* SdkResult.Error
  * ***error:*** Contains the error type needed according to the launched process/component.

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 correct completion of the Flow.

These fields are necessary for communication with the service of **Facephi**, if you want to perform any **verification** and if you 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}")
```

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

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

***

## Debug and error control options <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 an increase in debug logs so you can check 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 started correctly, certain settings can be applied to obtain more information about possible Tracking errors; monitoring can be carried out 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 events 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, actionable data.

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