> 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/sdks/sdk-mobile/android-sdk/ajustes-avanzados.md).

# Ajustes avanzados

## Introducción <a href="#id-1-introduccion" id="id-1-introduccion"></a>

En este apartado se amplía la información general del lanzamiento del SDK.

***

## Información avanzada del lanzamiento del SDK <a href="#id-2-informacion-avanzada-del-lanzamiento-del-sdk" id="id-2-informacion-avanzada-del-lanzamiento-del-sdk"></a>

En esta sección se va a ampliar la información del apartado de "Lanzamiento Simplificado del SDK".

### Añadir repositorio privado <a href="#id-21-anadir-repositorio-privado" id="id-21-anadir-repositorio-privado"></a>

Por cuestiones de seguridad y mantenimiento, los nuevos componentes de la ***SDKMobile*** se almacenan en unos repositorios privados que requieren de unas credenciales específicas para poder acceder a ellos. Esas credenciales deberá obtenerlas a través del *equipo de soporte* de **Facephi**.

Una vez obtenidas las credenciales, se deberá incluir el siguiente fragmento de código para configurar el repositorio maven en el **Gradle** de tu proyecto, o en el fichero **settings.gradle** del mismo. Se recomienda incluirlo tras *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")
    }
}
```

Para que el proyecto recupere correctamente las dependencias, se deberá tener las credenciales (Usuario y Token) configuradas correctamente

Hay varias formas de configurar las credenciales de acceso al repositorio:

* Como variables de entorno con el siguiente nombre. Por ejemplo:

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

  **Si las dependencia no las reconoce al sincronizar**, se deben incluir a través de variables de entorno en el archivo:

`~/.zshrc`

* Incluidos en el fichero *local.properties* con la siguiente estructura:

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

### Inicialización del SDK <a href="#id-22-inicializacion-del-sdk" id="id-22-inicializacion-del-sdk"></a>

**Debe evitarse inicializar un controlador que no vaya a usarse**.

El SDK funciona a través de un controlador principal (SDKController) que debe inicializarse correctamente para poder hacer uso del resto de funcionalidad. Los pasos a seguir en la inicialización son:

1. Incluir el objeto Application a través de la clase SdkApplication.
2. Decidir si la licencia se incluirá a través de un *String* o con un *servicio de licenciamiento remoto* (consultar **apartado 3.1**).
3. El controlador *TrackingController* en caso de querer conectar con la plataforma.

El **punto 3** es opcional, y requeriría usar el componente de Tracking (más información acerca de este módulo en su propia documentación).

Un ejemplo de inicialización sin *TrackingController* sería el siguiente:

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

Un ejemplo de inicialización con *TrackingController* sería el siguiente:

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

#### **Inyección de licencias**

Como se ha comentado previamente, actualmente existen dos formas de inyectar la licencia:

**a. Obteniendo la licencia a través de un servicio**

A través de un servicio que simplemente requerirá una URL y un API-KEY como identificador. Esto evitaría problemas a la hora de manipular la licencia, así como la constante sustitución de dichas licencias a la hora de surgir algún problema con ella (malformación o modificación indebida, expiración de la licencia...)

Ejemplo de implementación en 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}"
        )
}
```

Ejemplo de implementación en 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. Inyectando la licencia como String**

Se puede asignar la licencia directamente como un String, de la siguiente manera:

Ejemplo de implementación en 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}"
        )
}
```

Ejemplo de implementación en 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}")
    }
  }
);
```

#### **Recepción de errores**

En la parte del error, dispondremos de la clase SdkError.

Listado de errores:

* EMPTY\_LICENSE: Licencia vacía
* INIT\_AI\_MODELS(error: String): Error obtenido en el servicio de descarga de modelos
* INIT\_FLOW (error: String): Error obtenido en el servicio de descarga de flow
* LICENSE\_CHECKER\_ERROR (error: String): Error obtenido al verificar si la licencia es correcta
* LICENSING\_ERROR (error: String): Error obtenido en el servicio de descarga de licencias
* NETWORK\_CONNECTION\_ERROR: Error de conexión a internet
* TRACKING\_ERROR (error: String): Error obtenido al iniciar el controlador de tracking

***

## Iniciar nueva operación <a href="#id-3-iniciar-nueva-operacion" id="id-3-iniciar-nueva-operacion"></a>

Cada vez que se desee iniciar el flujo de alguna operación nueva (ejemplos de operaciones serían: *onboarding, authentication, videoCall*,...) es esencial indicarle al **SDKController** que ésta va a comenzar, y así la SDK sabrá que las próximas llamadas de **Componentes** (también llamados **Steps**) formarán parte de dicha operación.

Al iniciar un proceso o flujo, **siempre** se deberá realizar la llamada al método **newOperation**

Este método tiene los siguientes parámetros de entrada:

1. **operationType**: Indica si se va a hacer un proceso de ONBOARDING o de AUTHENTICATION.
2. **customerId**: Id único del usuario si se tiene (controlado a nivel de aplicación)
   1. Este parámetro aparecerá reflejado para cada operación en la plataforma.
3. **steps**: Lista de pasos de la operación si se han definido previamente
4. **enableTracking**: Permite activar o desactivar el envío de eventos de tracking para esta operación. Si no se informa, se considera `true`.

Hay 2 maneras de realizar este inicio de operación, dependiendo de si **se conocen los pasos** que formarán el flujo del proceso de registro o autenticación (en caso de que los componentes se ejecuten de forma secuencial y siempre de la misma forma) o, en caso contrario, de que el flujo **no esté definido** y sea desconocido (por ejemplo, el cliente final es el que decide el orden de ejecución de los componentes).

* Flujo **conocido** (aparecerá la operación *trackeada* en la plataforma con todos los pasos de la lista).

  Ejemplo de implementación Kotlin:

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

Ejemplo de implementación Java:

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

* Flujo **desconocido** (aparecerá la operación *trackeada* en la plataforma con puntos suspensivos). Ejemplo de implementación Kotlin:

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

Ejemplo de implementación Java:

```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` → Contiene en `data` la información de la operación creada.

Cuando el resultado es correcto, `data` es un `OperationResult` con:

| Campo         | Descripción                                                   |
| ------------- | ------------------------------------------------------------- |
| `sessionId`   | Identificador de la sesión creada o recuperada por el SDK.    |
| `operationId` | Identificador de la operación activa.                         |
| `type`        | Tipo de operación iniciado (`ONBOARDING` o `AUTHENTICATION`). |
| `customerId`  | Identificador de usuario asociado a la operación.             |

**Una vez creada la operación** se podrán ejecutar los componentes de la SDK asociados a esta operación. Consultar la documentación específica de cada componente para saber cómo hacerlo.

### **Tipos de operación existentes** <a href="#id-31-tipos-de-operacion-existentes" id="id-31-tipos-de-operacion-existentes"></a>

En la actualidad, existen las siguientes operaciones, durante las cuales se hacen uso de unos determinados **Componentes (STEPS).**

A continuación se muestra una tabla con la relación entre *operaciones* y *steps*:

| **Operación (OperationType)** | **Componente (Step)**                          | Descripción                                                                                                                              |
| ----------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| ONBOARDING                    | <p>SELPHI\_COMPONENT<br>SELPHID\_COMPONENT</p> | <p>- Validación facial de un selfie contra la cara de un documento<br>- Extracción del OCR del documento<br>- Detección de vivacidad</p> |
| AUTHENTICATION                | SELPHI\_COMPONENT                              | <p>- Validación facial mediante plantillas<br>- Detección de vivacidad</p>                                                               |

Esta lista se irá ampliando en próximas actualizaciones de la SDK, según vayan apareciendo nuevos componentes y casos de uso.

{% hint style="info" %}
Si la creación de una nueva operación devuelve un error del tipo **INTERNAL\_ERROR** se debe principalmente a un problema de **seguridad**. Para poder investigar la causa, es posible recuperar el token asociado al error, el cual proporciona información adicional para su análisis.

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

{% endhint %}

***

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

El SDK de Android incorpora un sistema de seguridad destinado a detectar y bloquear entornos potencialmente poco fiables o que puedan indicar intentos de ataque.<br>

Este mecanismo está habilitado por defecto, permite identificar situaciones que podrían comprometer la seguridad y previene la ejecución del SDK en contextos que no se consideran seguros:

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

***

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

La funcionalidad del SDK se divide en diferentes componentes con controladores particulares. Estos controladores se “lanzarán” desde el controlador general.

Una vez creada la **nueva operación** (**apartado 3**), se podrán lanzar los diferentes controladores de la SDK. Para consultar esta información se deberá acceder a la **documentación de cada uno de los componentes específicos**.

Ejemplo de lanzamiento Kotlin:

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

Ejemplo de lanzamiento Java:

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

### Opciones para el lanzamiento del componente <a href="#id-41-opciones-para-el-lanzamiento-del-componente" id="id-41-opciones-para-el-lanzamiento-del-componente"></a>

Una vez iniciado el SDK y creada una nueva operación se podrá lanzar el componente. Hay dos formas de lanzar el componente:

* **\[CON TRACKING]** Esta llamada permite lanzar la funcionalidad del componente con normalidad, pero sí se trackearán los eventos internos al servidor de *tracking*:

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

* **\[SIN TRACKING]** Esta llamada permite lanzar la funcionalidad del componente con normalidad, pero **no se trackeará** ningún evento al servidor de *tracking*:

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

El método **launch** debe usarse **por defecto**. Este método permite utilizar ***tracking*** en caso de estar su componente activado, y no lo usará cuando esté desactivado (o no se encuentre el componente instalado).

Por el contrario, el método **launchMethod** cubre un caso especial, en el cual el integrador tiene instalado y activado el tracking, pero en un flujo determinado dentro de la aplicación no desea trackear información. En ese caso se usa este método para evitar que se envíe esa información a la plataforma.

***

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

El resultado de cada componente será devuelto a través de la SDK manteniendo siempre la misma estructura a través de la clase ***SdkResult*** cuya clase es una Sealed Class que puede tener 2 posibles estados:

* SdkResult.Success: Indica que la operación ha finalizado correctamete y en su interior tiene:
  * ***data:*** Contiene el tipo de dato que sea necesario según el proceso/componente lanzado.
* SdkResult.Error
  * ***error:*** Contiene el tipo de error que sea necesario según el proceso/componente lanzado.

En la documentación de cada componente específico se desglosarán los diferentes campos que puede devolver este objeto

Ejemplo de uso:

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

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

***

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

En este apartado se incluyen otros controladores y operaciones auxiliares, algunos de ellos opcionales, y que pueden ser necesarios para la correcta finalización del flujo.

Estos campos son necesarios para la comunicación con el servicio de **Facephi**, en caso de querer realizar cualquier **verificación** y de desear realizar el *tracking* de una operación determinada.

### Obtención del 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}")
```

### Obtención del 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}")
```

### Obtención del 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}")
```

### Obtención del 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}")
```

### Asignación del CustomerID <a href="#id-65-asignacion-del-customerid" id="id-65-asignacion-del-customerid"></a>

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

***

## Opciones de depuración y control de errores <a href="#id-7-opciones-de-depuracion-y-control-de-errores" id="id-7-opciones-de-depuracion-y-control-de-errores"></a>

Existen ciertas opciones en el SDK que permiten un aumento en los logs de depuración para poder comprobar que todo funciona de manera correcta.

### Control de errores en las conexiones de Tracking con la plataforma <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>

Una vez el SDK se haya iniciado correctamente, se pueden aplicar ciertos ajustes para tener una mayor información acerca de los posibles errores en tracking, se puede realizar un seguimiento a través de este lanzamiento de controlador:

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

### Activación de Logs de depuración general <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()
 }
```

***

## Seguimiento y Análisis de Eventos en la Aplicación <a href="#id-8-seguimiento-y-analisis-de-eventos-en-la-aplicacion" id="id-8-seguimiento-y-analisis-de-eventos-en-la-aplicacion"></a>

La funcionalidad de eventos permite registrar e interpretar interacciones clave dentro de la aplicación, como cambios de pantalla y acciones del usuario, facilitando el análisis del comportamiento en tiempo real.

Cada evento se envía con un sello de tiempo, tipo y detalle específico, proporcionando un seguimiento estructurado y optimizando la experiencia del usuario con datos precisos y accionables.

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