¿Cómo puede un equipo de desarrollo integrar el SDK móvil de DIGID en su app?

¿Cómo puede un equipo de desarrollo integrar el SDK móvil de DIGID en su app?

Hay dos formas de llevar firma electrónica y verificación de identidad a una aplicación móvil. La primera es construir toda la experiencia desde cero: diseñar las pantallas, gestionar la cámara, implementar la captura de selfie, manejar el liveness check, integrar la lógica biométrica y mantener todo eso en el tiempo. La segunda es usar el SDK de DIGID.

El SDK embebe todo el front-end de DIGID — los flujos completos de KYC y firma — directamente dentro de la app del cliente. El equipo de desarrollo inicializa el SDK, lanza una vista y recibe el resultado. El diseño de pantallas, la lógica de cámara, la prueba de vida, la captura de firma: todo lo gestiona el SDK internamente.

Qué hace el SDK exactamente

El SDK de DIGID está disponible para Android (Kotlin) e iOS (Swift). Cubre dos flujos completos:

Verificación de identidad (KYC): captura de documento oficial por ambos lados, selfie y prueba de vida. El SDK gestiona la cámara, la guía al usuario paso a paso y entrega el resultado biométrico completo — face match, liveness score, datos del documento — al callback de la app.

Firma electrónica de documentos: flujo de cuatro pasos donde el usuario lee el PDF completo, toma una selfie, dibuja su firma y aplica las firmas en las posiciones definidas en el documento. Cada paso es una vista independiente que el equipo puede conectar con su propia lógica entre medias.

El equipo de desarrollo no construye ninguna de esas pantallas. Las lanza, recibe los resultados y decide qué hacer con ellos.

Instalación

Android: el SDK se distribuye como artefacto Maven en un repositorio público de GitHub, sin credenciales de descarga.

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/digid-mexico/sdk-kotlin-releases/main/repository") }
    }
}

// build.gradle.kts (módulo app)
dependencies {
    implementation("com.digid:digid-sdk:3.4.0"

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/digid-mexico/sdk-kotlin-releases/main/repository") }
    }
}

// build.gradle.kts (módulo app)
dependencies {
    implementation("com.digid:digid-sdk:3.4.0"

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/digid-mexico/sdk-kotlin-releases/main/repository") }
    }
}

// build.gradle.kts (módulo app)
dependencies {
    implementation("com.digid:digid-sdk:3.4.0"

iOS: se distribuye como XCFramework binario vía Swift Package Manager. En Xcode: File → Add Package Dependencies → https://github.com/digid-mexico/sdk-ios-releases, versión 1.13.0.

Versiones mínimas requeridas: Android API 24 (Android 7.0), iOS 14.

Inicialización

El SDK se inicializa una sola vez al arrancar la app — en Application.onCreate en Android, en App.init en iOS. Recibe las credenciales de la empresa, el ambiente (sandbox o producción) y la personalización visual.

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Digid.initialize(
            context     = this,
            clientId    = BuildConfig.DIGID_CLIENT_ID,
            token       = BuildConfig.DIGID_TOKEN,
            environment = DigidEnvironment.SANDBOX,
            theme = DigidTheme(
                primaryColor    = "#1A3C6E",
                secondaryColor  = "#2D8CF0",
                backgroundColor = "#FFFFFF"
            ),
            termsConfig = DigidTermsConfig

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Digid.initialize(
            context     = this,
            clientId    = BuildConfig.DIGID_CLIENT_ID,
            token       = BuildConfig.DIGID_TOKEN,
            environment = DigidEnvironment.SANDBOX,
            theme = DigidTheme(
                primaryColor    = "#1A3C6E",
                secondaryColor  = "#2D8CF0",
                backgroundColor = "#FFFFFF"
            ),
            termsConfig = DigidTermsConfig

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Digid.initialize(
            context     = this,
            clientId    = BuildConfig.DIGID_CLIENT_ID,
            token       = BuildConfig.DIGID_TOKEN,
            environment = DigidEnvironment.SANDBOX,
            theme = DigidTheme(
                primaryColor    = "#1A3C6E",
                secondaryColor  = "#2D8CF0",
                backgroundColor = "#FFFFFF"
            ),
            termsConfig = DigidTermsConfig

Las credenciales — clientId y token — nunca deben ir en el código fuente. El SDK las almacena internamente con EncryptedSharedPreferences en Android y Keychain en iOS. La recomendación es pasarlas desde BuildConfig en Android o ProcessInfo.environment en iOS.

El DigidTheme controla los colores de todas las pantallas del SDK: botones, indicadores, fondos. La app puede pasar sus propios colores de marca para que las pantallas del SDK sean coherentes con el resto de la experiencia.

Módulo KYC

Para lanzar el flujo de verificación de identidad, el equipo registra un launcher, lanza la actividad con el identificador del usuario y procesa el resultado en el callback.

val kycLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    when (result.resultCode) {
        Activity.RESULT_OK -> {
            val kycResult: KycResult? = Digid.consumeKycResult()
            kycResult?.let { onKycSuccess(it) }
        }
        DigidResultCode.RESULT_CANCELLED -> onKycCancelled()
        DigidResultCode.RESULT_ERROR -> {
            val error = result.data
                ?.getSerializableExtra(KycActivity.EXTRA_ERROR) as? DigidException
            onKycError(error)
        }
    }
}

fun startKyc() {
    val intent = Intent(this, KycActivity::class.java).apply {
        putExtra(KycActivity.EXTRA_VENDOR_DATA, "user_id_12345")
    }
    kycLauncher.launch(intent

val kycLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    when (result.resultCode) {
        Activity.RESULT_OK -> {
            val kycResult: KycResult? = Digid.consumeKycResult()
            kycResult?.let { onKycSuccess(it) }
        }
        DigidResultCode.RESULT_CANCELLED -> onKycCancelled()
        DigidResultCode.RESULT_ERROR -> {
            val error = result.data
                ?.getSerializableExtra(KycActivity.EXTRA_ERROR) as? DigidException
            onKycError(error)
        }
    }
}

fun startKyc() {
    val intent = Intent(this, KycActivity::class.java).apply {
        putExtra(KycActivity.EXTRA_VENDOR_DATA, "user_id_12345")
    }
    kycLauncher.launch(intent

val kycLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    when (result.resultCode) {
        Activity.RESULT_OK -> {
            val kycResult: KycResult? = Digid.consumeKycResult()
            kycResult?.let { onKycSuccess(it) }
        }
        DigidResultCode.RESULT_CANCELLED -> onKycCancelled()
        DigidResultCode.RESULT_ERROR -> {
            val error = result.data
                ?.getSerializableExtra(KycActivity.EXTRA_ERROR) as? DigidException
            onKycError(error)
        }
    }
}

fun startKyc() {
    val intent = Intent(this, KycActivity::class.java).apply {
        putExtra(KycActivity.EXTRA_VENDOR_DATA, "user_id_12345")
    }
    kycLauncher.launch(intent

El resultado llega como objeto nativo KycResult con todo lo que el sistema necesita para tomar una decisión:

fun onKycSuccess(result: KycResult) {
    val aprobado       = result.isApproved       // Boolean
    val faceMatch      = result.faceMatchScore   // Double 0–100
    val liveness       = result.livenessCheck    // Boolean
    val livenessScore  = result.livenessScore    // Double 0–100
    val documentValid  = result.documentValid    // Boolean
    val nombre         = result.document.fullName
    val curp           = result.document.personalNumber
    val sessionId      = result.sessionId

fun onKycSuccess(result: KycResult) {
    val aprobado       = result.isApproved       // Boolean
    val faceMatch      = result.faceMatchScore   // Double 0–100
    val liveness       = result.livenessCheck    // Boolean
    val livenessScore  = result.livenessScore    // Double 0–100
    val documentValid  = result.documentValid    // Boolean
    val nombre         = result.document.fullName
    val curp           = result.document.personalNumber
    val sessionId      = result.sessionId

fun onKycSuccess(result: KycResult) {
    val aprobado       = result.isApproved       // Boolean
    val faceMatch      = result.faceMatchScore   // Double 0–100
    val liveness       = result.livenessCheck    // Boolean
    val livenessScore  = result.livenessScore    // Double 0–100
    val documentValid  = result.documentValid    // Boolean
    val nombre         = result.document.fullName
    val curp           = result.document.personalNumber
    val sessionId      = result.sessionId

Un detalle importante: el resultado KYC no viaja en el Intent porque puede contener cuatro imágenes y superar el límite de Binder (~1 MB). Se recupera con Digid.consumeKycResult(), que es de un solo uso — la primera llamada devuelve el resultado y lo libera de memoria.

DIGID entrega el resultado de la validación biométrica; la decisión de negocio — aprobar, rechazar, escalar a revisión — la define la lógica del sistema del cliente.

Módulo de firma

El flujo de firma se compone de cuatro vistas que el equipo encadena con su propia lógica entre medias:

Vista

Qué hace

1 — Lectura del documento

El usuario lee el PDF completo. El botón Continuar se habilita al llegar al final.

2 — Captura de selfie

Selfie para validar identidad dentro del flujo de firma.

3 — Captura de firma

Lienzo táctil donde el usuario dibuja su firma. Soporta orientación horizontal.

4 — Aplicación de firmas

El usuario acepta cada punto de firma. Al completar, el documento se firma digitalmente.

Cada vista recibe tres parámetros: document_id, client_id y signer_id. Las vistas se lanzan de forma secuencial; entre cada una el equipo puede insertar validaciones, actualizar su base de datos o mostrar pantallas propias.

// Vista 1 — Lectura
fun openDocumentReader() {
    val intent = Intent(this, SignatureReadActivity::class.java).apply {
        putExtra(SignatureReadActivity.EXTRA_DOCUMENT_ID, "doc_abc123")
        putExtra(SignatureReadActivity.EXTRA_CLIENT_ID, "48")
        putExtra(SignatureReadActivity.EXTRA_SIGNER_ID, "signer_001")
    }
    readLauncher.launch(intent)
}

// Vista 4 — Aplicación de firmas (resultado final)
fun onSigningComplete(result: SignatureApplyResult) {
    if (result.isFullySigned) showSuccessScreen

// Vista 1 — Lectura
fun openDocumentReader() {
    val intent = Intent(this, SignatureReadActivity::class.java).apply {
        putExtra(SignatureReadActivity.EXTRA_DOCUMENT_ID, "doc_abc123")
        putExtra(SignatureReadActivity.EXTRA_CLIENT_ID, "48")
        putExtra(SignatureReadActivity.EXTRA_SIGNER_ID, "signer_001")
    }
    readLauncher.launch(intent)
}

// Vista 4 — Aplicación de firmas (resultado final)
fun onSigningComplete(result: SignatureApplyResult) {
    if (result.isFullySigned) showSuccessScreen

// Vista 1 — Lectura
fun openDocumentReader() {
    val intent = Intent(this, SignatureReadActivity::class.java).apply {
        putExtra(SignatureReadActivity.EXTRA_DOCUMENT_ID, "doc_abc123")
        putExtra(SignatureReadActivity.EXTRA_CLIENT_ID, "48")
        putExtra(SignatureReadActivity.EXTRA_SIGNER_ID, "signer_001")
    }
    readLauncher.launch(intent)
}

// Vista 4 — Aplicación de firmas (resultado final)
fun onSigningComplete(result: SignatureApplyResult) {
    if (result.isFullySigned) showSuccessScreen

La respuesta de la vista final confirma cuántas firmas se aplicaron y si el documento está completamente firmado:

{
  "success": true,
  "message": "Documento firmado digitalmente.",
  "signatures_applied": 3,
  "signatures_required": 3
}
{
  "success": true,
  "message": "Documento firmado digitalmente.",
  "signatures_applied": 3,
  "signatures_required": 3
}
{
  "success": true,
  "message": "Documento firmado digitalmente.",
  "signatures_applied": 3,
  "signatures_required": 3
}

Modo sin conexión

Una de las capacidades más relevantes del SDK para operaciones en campo es que tanto KYC como firma funcionan sin conexión a internet en el momento de la captura.

Firma offline: el operador puede leer el documento y capturar su firma sin cobertura. El SDK gestiona la operación localmente y sincroniza cuando vuelve la conexión. Es útil en almacenes, zonas industriales, bodegas o cualquier punto donde la cobertura es intermitente.

KYC offline: la captura biométrica — foto del documento, selfie, prueba de vida — también puede realizarse sin conexión. El procesamiento biométrico se ejecuta cuando el dispositivo recupera conectividad. Esto permite completar el onboarding de un operador o verificar la identidad de un cliente en ubicaciones remotas sin depender de señal en el momento exacto.

El caso de uso es claro en logística: un chofer que firma el acta de asignación de unidad en una bodega sin señal, o un operador de campo que completa su KYC en una instalación remota. El SDK captura, almacena de forma segura y sincroniza después.

Personalización visual y Términos y Condiciones

El SDK muestra automáticamente la pantalla de Términos y Condiciones de DIGID la primera vez que el usuario abre un flujo, o cuando expira el TTL de aceptación (15 minutos por defecto, configurable). Si la app ya tiene sus propios términos en el registro o inicio de sesión, DIGID puede deshabilitar esa pantalla por client_id sin ningún cambio de código.

La apariencia visual es completamente configurable. DigidTheme controla los colores de botones, fondos, indicadores y acentos en todas las pantallas del SDK. Si se pasa el logo de la empresa, aparece en el encabezado de cada pantalla en lugar del logo de DIGID.

Gestión de errores

Todos los errores del SDK se encapsulan en DigidException (Android) o DigidError (iOS) con un código específico. Los más relevantes en implementación:

fun handleDigidError(error: DigidException?) {
    when (error?.code) {
        DigidErrorCode.INVALID_TOKEN            -> showTokenExpiredDialog()
        DigidErrorCode.NETWORK_ERROR            -> showNetworkErrorDialog()
        DigidErrorCode.CAMERA_PERMISSION_DENIED -> requestCameraPermission()
        DigidErrorCode.KYC_FACE_NO_MATCH        -> showVerificationFailed()
        DigidErrorCode.KYC_LIVENESS_FAILED      -> showLivenessFailed()
        DigidErrorCode.DUPLICATE_SESSION_ID     -> retryWithNewSessionId()
        DigidErrorCode.DOCUMENT_NOT_FOUND       -> showDocumentNotFoundError()
        else                                    -> reportUnknownError(error

fun handleDigidError(error: DigidException?) {
    when (error?.code) {
        DigidErrorCode.INVALID_TOKEN            -> showTokenExpiredDialog()
        DigidErrorCode.NETWORK_ERROR            -> showNetworkErrorDialog()
        DigidErrorCode.CAMERA_PERMISSION_DENIED -> requestCameraPermission()
        DigidErrorCode.KYC_FACE_NO_MATCH        -> showVerificationFailed()
        DigidErrorCode.KYC_LIVENESS_FAILED      -> showLivenessFailed()
        DigidErrorCode.DUPLICATE_SESSION_ID     -> retryWithNewSessionId()
        DigidErrorCode.DOCUMENT_NOT_FOUND       -> showDocumentNotFoundError()
        else                                    -> reportUnknownError(error

fun handleDigidError(error: DigidException?) {
    when (error?.code) {
        DigidErrorCode.INVALID_TOKEN            -> showTokenExpiredDialog()
        DigidErrorCode.NETWORK_ERROR            -> showNetworkErrorDialog()
        DigidErrorCode.CAMERA_PERMISSION_DENIED -> requestCameraPermission()
        DigidErrorCode.KYC_FACE_NO_MATCH        -> showVerificationFailed()
        DigidErrorCode.KYC_LIVENESS_FAILED      -> showLivenessFailed()
        DigidErrorCode.DUPLICATE_SESSION_ID     -> retryWithNewSessionId()
        DigidErrorCode.DOCUMENT_NOT_FOUND       -> showDocumentNotFoundError()
        else                                    -> reportUnknownError(error

Un detalle de DUPLICATE_SESSION_ID: si el integrador envía su propio session_id y ya existe una verificación con ese identificador para ese cliente, el servidor la rechaza antes de crear la sesión — sin consumir ningún folio. El sistema simplemente genera un nuevo identificador y reintenta.

Buenas prácticas para la integración

Credenciales: almacenar siempre en BuildConfig o variables de entorno, nunca en el código fuente.

Inicialización temprana: inicializar el SDK en Application.onCreate, no en el momento en que el usuario va a usarlo, para evitar latencia y precargar la configuración de la empresa.

Permisos de cámara: solicitarlos antes de lanzar cualquier vista del SDK, con una explicación clara del motivo.

Sandbox primero: el sandbox de DIGID funciona igual que producción — mismo flujo, mismos callbacks, resultados reales. Probar el flujo completo en dispositivo físico antes de salir a producción; los emuladores no tienen cámara real y el liveness check puede comportarse distinto.

Datos biométricos: no loguear el JSON completo del resultado en producción. Las imágenes Base64 y la URL del video caducan (el video en 24 horas); descargar antes de que expiren si necesitan almacenarse.

Preguntas frecuentes

¿El SDK funciona con cualquier diseño de app? Sí. DigidTheme permite configurar colores y logo para que las pantallas del SDK sean coherentes con la identidad visual de la app. Las pantallas del SDK se abren como actividades/view controllers sobre la app del cliente.

¿Qué permisos necesita la app declarar? Ninguno explícitamente — el SDK los incluye en su propio AAR/XCFramework y el manifest merger los fusiona automáticamente. Solo es necesario declarar NSLocationWhenInUseUsageDescription en iOS cuando el documento requiere ubicación GPS.

¿El resultado KYC llega al backend automáticamente? No. El SDK entrega el resultado a la app mediante el callback; es la app quien decide cómo y cuándo enviarlo al backend. El resultado incluye un método toJson() que serializa la respuesta con el mismo contrato del API REST de DIGID, listo para enviarse directamente.

¿Cuánto tarda en completarse el KYC desde la app? El flujo de captura (documento + selfie + liveness) toma entre 1 y 3 minutos para el usuario. El procesamiento biométrico en servidores ocurre después de la captura; el SDK notifica el resultado al callback cuando el análisis está completo.

¿Se pueden usar los módulos de KYC y firma de forma independiente? Sí. Cada módulo es completamente independiente. Una app puede integrar solo KYC, solo firma, o ambos según lo que el flujo de negocio requiera.

Integra firma electrónica y KYC nativamente en tu app

El SDK de DIGID lleva los flujos completos de verificación de identidad y firma electrónica a cualquier aplicación móvil, sin construir ni mantener esa experiencia desde cero.

Solicita acceso al sandbox y empieza a integrar.

digid banner bg

Firma y protege tus contratos digitales con DIGID

Gestiona contratos digitales de forma inteligente

digid banner bg

Firma y protege tus contratos digitales con DIGID

Gestiona contratos digitales de forma inteligente