Skip to main content

Prueba de Vida

Descripción General

El SDK DicioLivenessUI para SwiftUI permite integrar un flujo de prueba de vida. Con este SDK, tu aplicación podrá validar la autenticidad del rostro del usuario y confirmar que el usuario está presente (liveness), reduciendo intentos de suplantación.

Funcionalidad de la Librería

  • Captura del rostro a través de la cámara.
  • Guía visual y opcionalmente con audio (vocal guidance) para el usuario.
  • Subida automática de datos para validación en el backend de FaceTec.
  • Retorno de resultados (imagen en base64, JSON de verificación, estatus de éxito o no).

Compatibilidad

LenguajeVersión iOS
SwiftUIiOS 15+

Incrustar y Firmar el Framework

  1. Añade DicioLivenessUI.xcframework al proyecto.
  2. En Xcode, en tu target -> pestaña “General”, ubica la sección “Frameworks, Libraries and Embedded Content” y arrastra el framework.
  3. Selecciona “Embed & Sign” en la columna “Embed”.

Requisitos Previos

  1. Permisos en el Info del proyecto: Asegúrate de agregar los siguientes permisos en la sección Info del target del proyecto o al archivo Info.plist:
   <key>NSCameraUsageDescription</key>
<string>Por favor, concede permisos al uso de la cámara. By Dicio</string>
  1. Archivos Necesarios:
  • DicioLivenessUI.framework
  • Carpeta VocalGuidanceSoundFiles (contiene archivos .mp3)
  • Archivo FaceTec.strings (para traducir textos de FaceTec)
  • Assets.xcassets (si tu framework usa ciertos assets específicos)

Asegúrate de que todos aparezcan en Build Phases -> Copy Bundle Resources (si se requiere).

Personalizar la Apariencia

Usa la struct LivenessUIConfig para definir colores (en hex) y el logo que se mostrará en la interfaz:

let uiConfig = LivenessUIConfig(
outerColorFondo: "#FFFFFF",
colorFrame: "#F5F5F5",
colorBorde: "#FF5733",
colorOvalo: "#AABBCC",
colorSpinnerDual: "#0080FF",
colorTexto: "#000000",
colorBtnYFeedbackBar: "#FF0000",
colorBtnAndFeedbackBarText: "#FFFFFF",
colorBtnHighlight: "#CC0000",
colorBtnDisabled: "#EFEFEF",
livenessLogo: "MiLogoEnAssets"
)

Parámetros:

  • outerColorFondo: Define el color de fondo en la interfaz de la prueba de vida.

    Archivos
  • colorFrame: Color de la subvista donde se encuentran las propiedades y la vista previa de la cámara.

    Archivos
  • colorBorde: Define el color para el frame que divide la vista principal y la subvista de las instrucciones.

    Archivos
  • colorOvalo: Aquí establecemos el color del borde que tiene la vista previa de la cámara.

    Archivos
  • colorSpinnerDual: Color de la animación en la interfaz cuando la prueba de vida está trabajando en la detección facial.

    Archivos
  • colorTexto: Color del texto de las instrucciones en la prueba de vida.

    Archivos
  • colorBtnYFeedbackBar: Color del fondo en el botón que recurrentemente aparece en la interfaz.

    Archivos
  • colorBtnAndFeedbackBarText: Color del texto en el botón que recurrentemente aparece en la interfaz.

    Archivos
  • livenessLogo: En esta propiedad podemos establecer el nombre del logotipo que queremos mostrar en la interfaz de la prueba de vida. Es muy importante mencionar que el logotipo deberá ser agregado en le catalogo ‘Assets’ del proyecto y solo se deberá ingresar el nombre del archivo.

Nota
  • Debemos asegurarnos de que los valores de color estén en formato hexadecimal adecuado.
  • El logo debe estar correctamente agregado al Assets Catalog del proyecto.
  • Todos los parámetros son obligatorios para asegurar el correcto funcionamiento del SDK.

Personalización de textos(opcional)

Crea un archivo FaceTec.strings para sobreescribir los textos por defecto de FaceTec. Ejemplo:

"FaceTec_presession_hold_steady_3" = "Manténte quieto durante: 3";
"FaceTec_presession_hold_steady_2" = "Manténte quieto durante: 2";
"FaceTec_presession_hold_steady_1" = "Manténte quieto durante: 1";
"FaceTec_instructions_header_ready_1" = "Prepárate para";
"FaceTec_instructions_header_ready_2" = "tu videoselfie";
"FaceTec_instructions_message_ready_1" = "Encuadra tu rostro en el óvalo";
"FaceTec_instructions_message_ready_2" = "Presiona Estoy listo y acércate";
"FaceTec_action_ok" = "Aceptar";
"FaceTec_action_im_ready" = "Estoy listo";
"FaceTec_action_try_again" = "Intentar nuevamente";
"FaceTec_action_continue" = "Continuar";
"FaceTec_action_take_photo" = "Tomar foto";
"FaceTec_action_accept_photo" = "Aceptar";
"FaceTec_action_retake_photo" = "Volver";
"FaceTec_action_confirm" = "Confirmar información";
"FaceTec_accessibility_cancel_button" = "Cancelar";
"FaceTec_accessibility_tap_guidance" = "Toque dos veces cualquier parte de la pantalla para ver indicaciones sobre cómo alinear el rostro.";
"FaceTec_accessibility_key_down_guidance" = "Presione Entrar o la barra espaciadora para obtener orientación sobre la alineación de la cara";
"FaceTec_accessibility_feedback_move_phone_away" = "Su rostro está demasiado cerca";
"FaceTec_accessibility_feedback_move_phone_closer" = "Su rostro está demasiado lejos";
"FaceTec_accessibility_feedback_face_too_far_left" = "Su rostro está demasiado a la izquierda";
"FaceTec_accessibility_feedback_face_too_far_right" = "Su rostro está demasiado a la derecha";
"FaceTec_accessibility_feedback_face_too_low" = "Su rostro está demasiado abajo";
"FaceTec_accessibility_feedback_face_too_high" = "Su rostro está demasiado arriba";
"FaceTec_accessibility_feedback_face_rotated_too_far_left" = "Su rostro gira demasiado a la izquierda";
"FaceTec_accessibility_feedback_face_rotated_too_far_right" = "Su rostro gira demasiado a la derecha";
"FaceTec_accessibility_feedback_face_looking_too_far_left" = "Su rostro está demasiado inclinado hacia la izquierda";
"FaceTec_accessibility_feedback_face_looking_too_far_right" = "Su rostro está demasiado inclinado hacia la derecha";
"FaceTec_accessibility_feedback_face_not_in_camera" = "El rostro no se ve en la cámara o está demasiado lejos";
"FaceTec_accessibility_feedback_hold_phone_to_eye_level" = "Mantenga el dispositivo a la altura de los ojos";
"FaceTec_accessibility_feedback_move_away_web" = "Cámara demasiado cerca";
"FaceTec_accessibility_feedback_move_closer_web" = "Cámara demasiado lejos";
"FaceTec_accessibility_feedback_hold_to_eye_level_web" = "Mover la cámara al nivel de los ojos";
"FaceTec_presession_frame_your_face" = "Encuadra tu rostro en el óvalo";
"FaceTec_presession_look_straight_ahead" = "Mira hacia el frente";
"FaceTec_presession_hold_steady3" = "No te muevas durante = 3";
"FaceTec_presession_hold_steady2" = "No te muevas durante = 2";
"FaceTec_presession_hold_steady1" = "No te muevas durante = 1";
"FaceTec_presession_eyes_straight_ahead" = "Mira hacia el frente";
"FaceTec_presession_remove_dark_glasses" = "Retírate los lentes oscuros";
"FaceTec_presession_neutral_expression" = "Expresión neutra, sin sonreír";
"FaceTec_presession_conditions_too_bright" = "Demasiada luz";
"FaceTec_presession_brighten_your_environment" = "Ilumina su entorno";
"FaceTec_feedback_center_face" = "Centra tu rostro";
"FaceTec_feedback_face_not_found" = "Encuadra tu rostro";
"FaceTec_feedback_move_phone_away" = "Apártate";
"FaceTec_feedback_move_away_web" = "Apártate";
"FaceTec_feedback_move_phone_closer" = "Acércate";
"FaceTec_feedback_move_web_closer" = "Acerca la cara y rellena el óvalo";
"FaceTec_feedback_move_web_even_closer" = "Aún Más Cerca";
"FaceTec_feedback_move_phone_to_eye_level" = "Coloca la cámara a la altura de los ojos";
"FaceTec_feedback_move_to_eye_level_web" = "Mira directamente a la cámara";
"FaceTec_feedback_face_not_looking_straight_ahead" = "Mira hacia el frente";
"FaceTec_feedback_face_not_upright" = "Manten la cabeza recta";
"FaceTec_feedback_face_not_upright_mobile" = "Manten la cabeza recta";
"FaceTec_feedback_hold_steady" = "Mantente estable";
"FaceTec_feedback_use_even_lighting" = "Ilumina el rostro de forma más uniforme";
"FaceTec_instructions_header_ready_desktop" = "Prepárate para tu videoselfie";
"FaceTec_instructions_header_ready_1_mobile" = "Prepárate para";
"FaceTec_instructions_header_ready_2_mobile" = "tu videoselfie";
"FaceTec_instructions_message_ready_desktop" = "Encuadra tu rostro en el óvalo, Presiona \"Estoy listo\" y acércate";
"FaceTec_instructions_message_ready_1_mobile" = "Encuadra tu rostro en el óvalo";
"FaceTec_instructions_message_ready_2_mobile" = "Presiona \"Estoy listo\" y acércate";
"FaceTec_retry_header" = "Inténtelo otra vez";
"FaceTec_retry_subheader_message" = "Necesitamos una videoselfie más clara";
"FaceTec_retry_your_image_label" = "Tu selfie";
"FaceTec_retry_ideal_image_label" = "Postura ideal";
"FaceTec_retry_instruction_message_1" = "Usar una postura e iluminación ideal";
"FaceTec_retry_instruction_message_2" = "Expresión neutra, sin sonreír";
"FaceTec_retry_instruction_message_3" = "Demasiado borrosa, limpie la cámara";
"FaceTec_camera_feed_issue_header" = "Problema al proteger la conexión de la cámara";
"FaceTec_camera_feed_issue_header_mobile" = "Problema al proteger\nla conexión de la cámara";
"FaceTec_camera_feed_issue_subheader_message_mobile" = "Esta aplicación bloquea configuraciones de cámara web sospechosas.\n<a href='https://livenesscheckhelp.com/' target='_blank' style='text-decoration:underline; font:inherit; pointer-events:all;'>Aprende más aquí.</a>.";
"FaceTec_camera_feed_issue_subheader_message" = "No es posible continuar debido a lo siguiente:";
"FaceTec_camera_feed_issue_table_header_1" = "Posible Problema";
"FaceTec_camera_feed_issue_table_header_2" = "Corregir";
"FaceTec_camera_feed_issue_table_row_1_cell_1_firefox_permissions_error" = "Permisos de cámara no recordados en Firefox.";
"FaceTec_camera_feed_issue_table_row_1_cell_2_firefox_permissions_error" = "Marca Recordar Permisos.";
"FaceTec_camera_feed_issue_table_row_1_cell_1" = "Cámara ya en uso por otra aplicación.";
"FaceTec_camera_feed_issue_table_row_1_cell_2" = "Cierra la otra aplicación.";
"FaceTec_camera_feed_issue_table_row_2_cell_1" = "Una aplicación de terceros está modificando el video.";
"FaceTec_camera_feed_issue_table_row_2_cell_2" = "Cierre / desinstale la otra aplicación.";
"FaceTec_camera_feed_issue_table_row_3_cell_1" = "Equipos que no pueden ser protegidos.";
"FaceTec_camera_feed_issue_table_row_3_cell_2" = "Usa un dispositivo diferente.";
"FaceTec_camera_feed_issue_subtable_message" = "Esta aplicación bloquea configuraciones de cámara web sospechosas. <a href='https://livenesscheckhelp.com/' target='_blank' style='text-decoration:underline; font:inherit; pointer-events:all;'>Aprende más aquí.</a>.";
"FaceTec_camera_feed_issue_action" = "Intentar nuevamente";
"FaceTec_camera_feed_issue_action_firefox_permissions_error" = "Aceptar";
"FaceTec_camera_permission_header" = "Habilita la cámara";
"FaceTec_camera_permission_message" = "Permisos de cámara deshabilitados.\nVerifique la configuración de su sistema operativo y navegador";
"FaceTec_enter_fullscreen_header" = "Modo Selfie a Pantalla Completa";
"FaceTec_enter_fullscreen_message" = "Antes de comenzar, haga clic en el botón de abajo para abrir el modo de pantalla completa.";
"FaceTec_enter_fullscreen_action" = "Abrir pantalla completa";
"FaceTec_initializing_camera" = "Protegiendo la conexión";
"FaceTec_idscan_type_selection_header" = "Prepárese para escanear\nsu identificación";
"FaceTec_idscan_capture_id_front_instruction_message" = "Anverso de su identificación";
"FaceTec_idscan_capture_id_back_instruction_message" = "Reverso de su identificación";
"FaceTec_idscan_review_id_front_instruction_message" = "Verifique sea nítida y legible";
"FaceTec_idscan_review_id_back_instruction_message" = "Verifique sea nítida y legible";
"FaceTec_idscan_additional_review_message" = "Se requiere\nuna verificación adicional";
"FaceTec_idscan_ocr_confirmation_main_header" = "Revisar y confirmar";
"FaceTec_idscan_ocr_confirmation_scroll_message" = "Desplácese hacia abajo";
"FaceTec_idscan_feedback_flip_id_to_back_message" = "Reverso de su identificación";
"FaceTec_result_success_message" = "Listo";
"FaceTec_result_facescan_upload_message" = "Subiendo\nel escaneo facial 3D\ncifrado";
"FaceTec_result_idscan_upload_message" = "Subiendo\nel escaneo de identificación\ncifrado";
"FaceTec_result_idscan_unsuccess_message" = "La foto de la identificación\no coincide con\el rostro del usuario";
"FaceTec_result_idscan_success_front_side_message" = "Escaneo de identificación completado";
"FaceTec_result_idscan_success_front_side_back_next_message" = "Anverso de la identificación\nescaneado";
"FaceTec_result_idscan_success_back_side_message" = "Escaneo de identificación completado";
"FaceTec_result_idscan_success_passport_message" = "Escaneo de pasaporte completado";
"FaceTec_result_idscan_success_user_confirmation_message" = "Escaneo de identificación con fotografía\ncompletado";
"FaceTec_result_idscan_success_additional_review_message" = "Captura de la fotografía de identificación\ncompletada";
"FaceTec_result_idscan_retry_face_did_not_match_message" = "El rostro no coincide\nlo suficiente";
"FaceTec_result_idscan_retry_id_not_fully_visible_message" = "La identificación\nno es totalmente visible";
"FaceTec_result_idscan_retry_ocr_results_not_good_enough_message" = "El texto de la identificación no es legible";
"FaceTec_result_idscan_retry_id_type_not_suppported_message" = "No se admite este tipo de identificación\nUtilice una identificación diferente";
"FaceTec_result_idscan_retry_barcode_not_read_message" = "No se pudo escanear el código de barras\nInténtelo de nuevo";

El archivo debe incluirse en el bundle principal de la app.

Ejemplo de Uso

import SwiftUI
import DicioLivenessUI

struct MiVista: View, CaptureFaceResultsDelegate {
@State private var showFramework = false

func finishedLiveness(isSuccessfull: Bool, JSONResults: String, picBase64: String) {
if isSuccessfull {
// Maneja éxito.
print("Resultados: \(JSONResults), foto en base64: \(picBase64)")
} else {
print("Prueba de vida no exitosa.")
}
showFramework = false
}

var body: some View {
Button("Lanzar Liveness") {
showFramework = true
}
.fullScreenCover(isPresented: $showFramework) {
let configLV = LivenessUIConfig(
outerColorFondo: "#FFFFFF",
// ...
livenessLogo: "MiLogo"
)
LivenessLaunchView(config: configLV,
urlVerify: "https://api.devdicio.net:8444/v1/sec_dev_pagos_middleware",
token: "TOKEN PROPORCIONADO",
maxAttempts: 3,
soundEnable: true,
delegate: self
)
}
}
}

Implementación del Protocolo

Debes extender o conformar CaptureFaceResultsDelegate, que define un método:

func finishedLiveness(isSuccessfull: Bool, 
JSONResults: String,
picBase64: String) {
// Manejo de resultados
}

isSuccessfull: Indica si la prueba de vida fue satisfactoria.

JSONResults: Respuesta detallada (ej. JSON del backend).

picBase64: Foto del rostro capturado en base64.

Conclusiones

•   DicioLivenessUI facilita la prueba de vida mediante Facetec dentro de SwiftUI.
• Asegúrate de colocar los permisos Camera y Microphone en el Info.plist.
• Personaliza la interfaz de Liveness con DicioLivenessUI.
• Implementa CaptureFaceResultsDelegate para manejar resultados.

Consideraciones Adicionales

Manejo de Errores: El SDK internamente maneja casos de permisos denegados o token no autorizado. En caso de que el usuario deniegue la cámara o micrófono, se le mostrará una alerta indicándole que debe conceder permisos.

Estilos y UI: Puedes personalizar la presentación (por ejemplo, usar .sheet en lugar de .fullScreenCover), siempre que el contenedor sea una vista SwiftUI.

Integración en Proyectos Existentes: Asegúrate de que tu proyecto cumpla con iOS 13+ (o la versión que hayas definido). Para versiones anteriores, este SDK no es compatible.

Versionado: Verifica la versión específica de VideoRecorderUI.xcframework que recibas, en caso de que existan actualizaciones o cambios en la API.