> 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/ios-sdk/modulos/subida-de-ficheros-y-gestion-de-qr.md).

# Subida de ficheros y gestión de QR - Capture

## Introducción

La subida de ficheros y la lectura y generación de códigos QR se realizan con el ***Capture Component***.

Este componente permite la subida de documentos realizando una foto con la cámara del dispositivo o desde la galería. Sus principales funcionalidades son:

* Subida de documentos mediante cámara o galería.
* Lectura de códigos QR.
* Generación de códigos QR.

En el apartado de [Lanzamiento simplificado](/sdks/sdk-mobile/ios-sdk/inicializacion/lanzamiento-simplificado.md) se detallan los pasos necesarios para la integración básica del SDK. En esta sección se añade la información para el lanzamiento de este componente.

***

## Dependencias

Para evitar conflictos y problemas de compatibilidad, en caso de querer instalar el componente en un proyecto que contenga una versión antigua de las librerías de Facephi (Widgets), éstos deberán eliminarse por completo antes de la instalación de los componentes de la **SDKMobile**.

### **Cocoapods**

* Actualmente las librerías de Facephi se distribuyen de forma remota a través de diferentes gestores de dependencias, en este caso Cocoapods. Las dependencias **obligatorias** que deberán haberse instalado previamente (añadiéndolas en el fichero Podfile del proyecto) son:

```swift
pod 'FPHISDKMainComponent', '~> $VERSION'
```

* Para instalar el componente de Captura deberá incluirse la siguiente entrada en el Podfile de la aplicación:

```swift
pod 'FPHISDKCaptureComponent', '~> $VERSION'
```

### **SPM**

* Las dependencias obligatorias que deberán haberse instalado previamente son:

```swift
//HTTPS
https://github.com/facephi-clienters/SDK-SdkPackage-SPM.git
//SSH
git@github.com:facephi-clienters/SDK-SdkPackage-SPM.git
```

* Para instalar el componente de Selphid deberá incluirse en los módulos del proyecto:

<pre class="language-swift"><code class="lang-swift"><strong>//HTTPS
</strong>https://github.com/facephi-clienters/SDK-CapturePackage-SPM.git
//SSH
git@github.com:facephi-clienters/SDK-CapturePackage-SPM.git
</code></pre>

**IMPORTANTE: Si se está utilizando FileUploaderController mediante SPM. Los recursos y&#x20;*****assets*****&#x20;que el componente necesita requieren la ejecución de un script en cada construcción del target.**

Para hacer este proceso automático, el script debería añadirse en Target -> Build Phases -> + Run Script

```
set -euo pipefail
BUNDLE_PATH="${TARGET_BUILD_DIR}/FPHICaptureWidget-SPM_FPHICaptureWidget-SPM.bundle/compose-resources"
DESTINATION="${TARGET_BUILD_DIR}/${TARGET_NAME}.app/compose-resources"
if [ -d "$BUNDLE_PATH" ]; then
  rm -rf "$DESTINATION"
  mkdir -p "$DESTINATION"
  cp -R "$BUNDLE_PATH/" "$DESTINATION/"
  echo "Copied FPHICaptureWidget Compose resources to ${DESTINATION}"
else
  echo "FPHICaptureWidget Compose resources not found at ${BUNDLE_PATH}. If your app is not using FPHICaptureWidget Component anymore, delete the script from your Build Phases -> Run Script section"
  exit 1
fi

BUNDLE_PATH_DS="${TARGET_BUILD_DIR}/FPHIDesignSystemResources_FPHIDesignSystemResources.bundle/Resources/compose-resources"
DESTINATION="${TARGET_BUILD_DIR}/${TARGET_NAME}.app/compose-resources"
if [ -d "$BUNDLE_PATH_DS" ]; then
  cp -R "$BUNDLE_PATH_DS/" "$DESTINATION/"
  echo "Copied FPHIDesignSystemResources Compose resources to ${DESTINATION}"
else
  echo "FPHIDesignSystemResources Compose resources not found at ${BUNDLE_PATH_DS}. If your app is not using FacePhi Components anymore, delete the script from your Build Phases -> Run Script section"
  exit 1
fi
```

Es importante desmarcar la opción *For install builds only*.

**Si el script no es añadido, ocurrirá un crash en tiempo de ejecución cuando se haga el lanzamiento del FileUploaderController.**

***

## Controladores disponibles <a href="#id-3-controladores-disponibles" id="id-3-controladores-disponibles"></a>

| **Controlador**        | **Descripción**                           |
| ---------------------- | ----------------------------------------- |
| FileUploaderController | Controlador para la captura de documentos |
| QrReaderController     | Controlador para la captura de QRs        |
| QrGeneratorController  | Controlador para la generación de QRs     |

***

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

Una vez iniciado el SDK y creada una nueva operación se podrá lanzar el componente. Se podrá hacer uso de cualquiera de sus controladores para ejecutar su funcionalidad.

Lanzamiento de la captura de documentos:

```swift
let controller = FileUploaderController(data: fileUploaderConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

Lanzamiento de la captura de QR:

```swift
let controller = QrReaderController(data: qrReaderConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

Lanzamiento de la generación de QR:

```swift
let controller = QrGeneratorController(data: qrGeneratorConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

***

## Configuración básica <a href="#id-5-configuracion-basica" id="id-5-configuracion-basica"></a>

Para los controladores de captura de componentes y captura de QR se puede generar la configuración con los parámetros por defecto. Para el caso de la geneación del QR se necesitará el texto que se va a utilizar:

```
QrGeneratorConfiguration(source:"QR text")
```

***

## Recepción del resultado <a href="#id-6-recepcion-del-resultado" id="id-6-recepcion-del-resultado"></a>

El lanzamiento devolverá la información en formato SdkResult.

* errorType
* finishStatus
* data

### Recepción de errores <a href="#id-61-recepcion-de-errores" id="id-61-recepcion-de-errores"></a>

Los errores se devolverán como un objeto 'CaptureError'.

Listado de errores:

* CAP\_ACTIVITY\_RESULT\_MSG\_ERROR: El resultado devuelto por la actividad es incorrecto o no contiene la información necesaria para continuar.
* CAP\_APPLICATION\_CONTEXT\_ERROR: El contexto de aplicación requerido es nulo o no válido, impidiendo inicializar correctamente el módulo de captura.
* CAP\_CAMERA\_ERROR: Ha ocurrido un error interno relacionado con la cámara del dispositivo (fallo de apertura, inicialización o captura).
* CAP\_CAMERA\_PERMISSION\_DENIED: El usuario ha denegado los permisos necesarios para acceder a la cámara.
* CAP\_CANCEL\_BY\_USER: El usuario ha cancelado manualmente el proceso de captura.
* CAP\_CANCEL\_LAUNCH: El proceso ha sido cancelado de forma general por el SDK o por una acción externa.
* CAP\_COMPONENT\_LICENSE\_ERROR: La licencia del componente no es válida, ha expirado o no coincide con la configuración requerida.
* CAP\_EMPTY\_LICENSE: La cadena de licencia está vacía o no se ha proporcionado.
* CAP\_FETCH\_DATA\_ERROR: Se ha producido un error al obtener o procesar los datos necesarios para ejecutar el flujo. *(Incluye información adicional en el campo `error`.)*
* CAP\_FLOW\_ERROR: Se ha producido un error interno durante la ejecución del flujo de captura. *(Incluye información adicional en el campo `error`.)*
* CAP\_INITIALIZATION\_ERROR: Error al inicializar los componentes necesarios del SDK. *(Incluye información detallada en el campo `error`.)*
* CAP\_FILE\_UPLOADER\_CAPTURE\_ERROR: Error durante el proceso de subida de los archivos generados en la captura.
* CAP\_MANAGER\_NOT\_INITIALIZED: Los managers necesarios para ejecutar el proceso no han sido inicializados correctamente.
* CAP\_NO\_DATA\_ERROR: Los datos de entrada requeridos son nulos, inexistentes o insuficientes para continuar el proceso.
* CAP\_OPERATION\_NOT\_CREATED: No se ha podido crear o recuperar una operación activa necesaria para continuar. *(Incluye información detallada en el campo `error`.)*
* CAP\_QR\_CAPTURE\_ERROR: Error durante la captura o lectura del código QR.
* CAP\_QR\_GENERATION\_ERROR: Error al generar el código QR solicitado.
* CAP\_TIMEOUT: Se ha alcanzado el tiempo máximo permitido en alguna de las fases del proceso.
* CAP\_FLOW\_VIDEO\_RECORDING\_ERROR: Error durante la grabación de vídeo dentro del flujo establecido.
* CAP\_FLOW\_TRACKING\_ERROR: Error al realizar el tracking necesario para completar el flujo de captura.

### Recepción del resultado correcto - *data* <a href="#id-62-recepcion-del-resultado-correcto-data" id="id-62-recepcion-del-resultado-correcto-data"></a>

#### **Recepción del resultado de la captura de documentos**

En la parte de SdkResult.Success - *data*, dispondremos de la clase *FileUploaderResult*.

Los campos devueltos en el resultado son los siguientes:

***capturedDocumentList***

Listado de ficheros capturados. Pueden ser imágenes o PDFs. Los campos devueltos de cada uno son:

* mimeType
* timestampMillis
* content: FileContent -> determina si es una imagen o un documento PDF. Si es una imagen también se indica si se ha capturado con la cámara o desde la galería.

```
public enum FileContent {
    case uploaderImage(UploaderImage)
    case uploaderDocument(UploaderDocument)
    
    // MARK: - Nested types
    public struct UploaderImage {
        public let image: UIImage
        public let rotationDegrees: Int
        public let source: FileUploaderSource
    }
    
    public struct UploaderDocument {
        public let frontPageImage: UIImage?
        public let bytes: Data
    }
}

public enum FileUploaderSource: String {
    case CAMERA
    case GALLERY
}
```

Por ejemplo para leer el primer elemento del array:

```
(..., output: { fileUploaderResult in
    guard fileUploaderResult.errorType == .NO_ERROR else {
        print("\(fileUploaderResult.errorType)")
        return
    }
    ...
    let firstElement = fileUploaderResult.data?.documentImages.first
    
    switch firstElement?.content {
    case .uploaderDocument(let doc):
        // Do something with the file
        break
    case .uploaderImage(let image):
        // Do something with the image
        break
    case .none:
        break
    }
})
```

#### **Recepción del resultado de la captura de QR**

En la parte de SdkResult.Success - *data*, dispondremos de la clase *QrResult*.

Los campos devueltos en el resultado son los siguientes:

***qrText***

Texto obtenido del QR

#### **Recepción del resultado de la generación de QR**

En la parte de SdkResult.Success - *data*, dispondremos de una SdkImage con el QR creado.

***

## Información avanzada <a href="#id-7-informacion-avanzada" id="id-7-informacion-avanzada"></a>

Este apartado amplía la información del componente.

### Configuración avanzada del componente <a href="#id-71-configuracion-avanzada-del-componente" id="id-71-configuracion-avanzada-del-componente"></a>

#### **Configuración de la captura de documentos**

Para lanzar el componente actual, se deberá crear un objeto *FileUploaderConfigurationData* que será la configuración del controlador del componente.

A continuación se detallan todos los campos que forman parte de esta clase.

* `vibrationEnabled`: Indica la activación de la vibración cuando el widget termine satisfactoriamente.
* `extractionTimeout`: Establece el tiempo máximo que se puede realizar la captura.
* `showDiagnostic`: Mostrar pantallas de diagnóstico al final del proceso.
* `showPreviousTip`: Muestra una pantalla previa al lanzamiento de la captura con información sobre el proceso a realizar y un botón para el lanzamiento.
* `maxScannedDocs`: Número máximo de documentos que se podrán capturar
* `allowGallery`: Se habilita el acceso a la galería para la obtención de imágenes o PDFs
* `onlyGalleryMode`: Abre el flujo directamente en modo galería, sin mostrar la captura con cámara. Por defecto `true`.
* `maxGalleryImageSizeKb`: Tamaño máximo permitido para imágenes seleccionadas desde galería, en KB. Por defecto `2048`. Si una imagen supera este límite, el componente devuelve `CAP_IMAGE_TOO_LARGE`.

#### **Configuración de la captura de QR**

Para lanzar el componente actual, se deberá crear un objeto *QrCaptureConfigurationData* que será la configuración del controlador del componente.

A continuación se detallan todos los campos que forman parte de esta clase.

* `vibrationEnabled`: Indica la activación de la vibración cuando el widget termine satisfactoriamente.
* `extractionTimeout`: Establece el tiempo máximo que se puede realizar la captura.
* `showDiagnostic`: Mostrar pantallas de diagnóstico al final del proceso.
* `showPreviousTip`: Muestra una pantalla previa al lanzamiento de la captura con información sobre el proceso a realizar y un botón para el lanzamiento.
* `showTutorial`: Indica si el componente activa la pantalla de tutorial. En esta vista se explica de forma intuitiva cómo se realiza la captura.
* `cameraShape`: Permite elegir entre una máscara cuadrada y una redonda.

***

## Personalización del componente <a href="#id-8-personalizacion-del-componente" id="id-8-personalizacion-del-componente"></a>

Aparte de los cambios que se pueden realizar a nivel de SDK (los cuales se explican en el documento de *Personalización del SDK*), este componente en concreto permite la modificación de su interfaz.

### Textos <a href="#id-81-textos" id="id-81-textos"></a>

Los textos pueden personalizarse sobrescribiendo el valor de las siguientes claves en un **Localizable.strings**. Las claves que contienen el sufijo ***\_alt*** son los literales utilizados en las etiquetas de accesibilidad necesarias para la funcionalidad de ***VoiceOver***.

```xml
<resources>
    <!-- Previous Tip -->
    <string name="capture_component_qr_tip_title">Escanea el código QR</string>
    <string name="capture_component_qr_tip_message">&lt;b&gt; Enfoca &lt;/b&gt; el código QR &lt;b&gt; dentro del recuadro &lt;/b&gt;</string>
    <string name="capture_component_qr_tip_button">Comenzar</string>
    <string name="capture_component_qr_tip_anim_desc">Animación de un teléfono móvil haciendo una foto a un código QR. En la pantalla del móvil aparece un recuadro. Cuando el código QR encaja dentro del recuadro, la aplicación hace una foto.</string>
    <string name="capture_component_qr_tutorial_1_anim_desc">Se muestra un código QR sobre un fondo blanco. Los bordes del código QR no se distinguen con claridad. Mediante una animación, el fondo cambia de color.</string>
    <string name="capture_component_qr_tutorial_2_anim_desc">Un teléfono móvil hace una foto a un código QR. El código QR aparece en horizontal, y el móvil en posición vertical. En la pantalla del móvil aparece un recuadro. Cuando el código QR encaja dentro del recuadro, la aplicación hace una foto.</string>
    <!-- Tutorial -->
    <string name="capture_component_qr_tutorial_1">Asegúrate de que el código QR tiene &lt;b&gt; luz suficiente &lt;/b&gt; y &lt;b&gt; no hay reflejos &lt;/b&gt; o destellos sobre el código.</string>
    <string name="capture_component_qr_tutorial_2">Encaja los bordes del código QR dentro del recuadro.</string>
    <!-- Process -->
    <string name="capture_component_qr_camera_message">Mantén el QR en el centro</string>
    <string name="capture_component_button_message">Capturar</string>
    <!-- Diagnostic -->
    <string name="capture_component_timeout_title">Tiempo superado</string>
    <string name="capture_component_timeout_desc">Pedimos disculpas. No se ha podido hacer la captura</string>
    <string name="capture_component_internal_error_title">Hubo un problema técnico</string>
    <string name="capture_component_internal_error_desc">Pedimos disculpas. No se ha podido hacer la captura</string>

    <!-- WIDGET -->
    <!-- Previous Tip -->
    <string name="capture_widget_tip_title">Escanear documentos</string>
    <string name="capture_widget_tip_message">Haz una foto al documento, o sube una imagen.&lt;br&gt;&lt;br&gt; Puedes escanear varios documentos antes de finalizar.</string>
    <string name="capture_widget_tip_message_alt">Haz una foto al documento, o sube una imagen. Puedes escanear varios documentos antes de finalizar.</string>
    <string name="capture_widget_tip_button">Comenzar</string>
    <string name="capture_widget_tip_button_alt">Comenzar captura de documentos</string>
    <string name="capture_widget_tip_close_button_alt">Volver</string>
    <string name="capture_widget_tip_info_button_alt">Ver consejos</string>
    <string name="capture_widget_tip_anim_desc">Animación de un teléfono móvil haciendo una foto a un documento. En la pantalla del móvil aparece un recuadro. Cuando el documento encaja dentro del recuadro, la aplicación hace una foto.</string>
    <!-- Camera -->
    <string name="capture_widget_document_camera_button_gallery">Galería</string>
    <string name="capture_widget_document_camera_button_capture">Capturar</string>
    <string name="capture_widget_document_camera_button_cancel">Cancelar captura</string>
    <string name="capture_widget_document_camera_button_finish">Finalizar</string>
    <!-- Gallery -->
    <string name="capture_widget_gallery_images">Imágenes</string>
    <string name="capture_widget_gallery_pdf">Seleccionar PDF</string>
    <string name="capture_widget_gallery_cancel">Cancelar</string>
    <!-- Confirmation -->
    <string name="capture_widget_image_captured">Imagen capturada</string>
    <string name="capture_widget_confirmation_message">¿Todos los datos se leen de forma clara y nítida?</string>
    <string name="capture_widget_confirmation_retry">NO, QUIERO REPETIR LAS FOTOGRAFÍAS</string>
    <string name="capture_widget_confirmation_continue">Sí, finalizar</string>
    <string name="capture_widget_confirmation_delete">Borrar foto</string>
    <string name="capture_widget_confirmation_image_unavailable">Vista previa no disponible</string>
    <string name="capture_widget_confirmation_no_images">No hay capturas disponibles</string>
    <string name="capture_widget_confirmation_delete_dialog_title">¿Quieres eliminar este documento?</string>
    <string name="capture_widget_confirmation_delete_dialog_message">Al eliminar este documento no vas a poder recuperarlo. Deberás realizar una nueva fotografía.</string>
    <string name="capture_widget_confirmation_delete_dialog_cancel">CANCELAR</string>
    <string name="capture_widget_confirmation_delete_dialog_confirm">ELIMINAR DOCUMENTO</string>
    <!-- Diagnostic -->
    <string name="capture_widget_timeout_title">Tiempo superado</string>
    <string name="capture_widget_timeout_desc">Pedimos disculpas. No se ha podido hacer la captura</string>
    <string name="capture_widget_internal_error_title">Hubo un problema técnico</string>
    <string name="capture_widget_internal_error_desc">Pedimos disculpas. No se ha podido hacer la captura</string>

</resources>
```

De este modo, si se desea modificar por ejemplo el texto “*Comenzar*” de la clave `capture_widget_tip_button` para el idioma **es**, se deberá ir al archivo **Localizable.strings** de la carpeta **es.lproj** si es que existe (si no, se deberá crear) y ahí, añadir:

`"capture_widget_tip_button"="Start";`

Si un mensaje no se especifica en el fichero del idioma, este se rellenará con el mensaje por defecto.

### Animaciones <a href="#id-82-animaciones" id="id-82-animaciones"></a>

Si se desea modificar las animaciones (lottie) de la SDK habría que incluir las animaciones con el mismo nombre en la carpeta res/raw/ de la aplicación.

```
qr_anim_tip_1.json
qr_anim_tip_2.json
capture_anim_tip.json
```
