JAAK Stamps SDK Android




Introduccion

El JAAK Stamps SDK es una solucion completa para captura profesional de documentos de identidad en aplicaciones Android. El SDK automatiza todo el proceso de captura, desde la deteccion del documento hasta el recorte y extraccion de informacion visual.

Caracteristicas principales

  • Captura guiada con instrucciones visuales en tiempo real
  • Deteccion automatica de tipo de documento (frente/reverso)
  • Recorte inteligente del documento
  • Extraccion automatica del rostro del documento
  • Validacion de calidad de imagen
  • Soporte para INE, IFE, Pasaporte, Licencias, Cedulas
  • Interfaz de usuario personalizable
  • Optimizado para todos los rangos de dispositivos

Que hace el SDK

El SDK guia al usuario paso a paso para capturar documentos de identidad con calidad profesional:

  1. Detecta el documento automaticamente usando la camara
  2. Guia al usuario con instrucciones visuales (acercar, alejar, mantener estable)
  3. Valida la calidad en tiempo real (iluminacion, nitidez, alineacion)
  4. Captura automaticamente cuando detecta condiciones optimas
  5. Recorta el documento eliminando fondo y bordes innecesarios
  6. Extrae el rostro de la foto del documento (si esta presente)
  7. Determina si necesita reverso (INE/IFE) o solo frente (Pasaporte)
  8. Entrega multiples versiones de cada imagen (original, recortada, rostro)

Requisitos Previos

Requisitos Tecnicos

ComponenteVersion RequeridaNotas
Android StudioIguana o superiorIDE recomendado
Gradle8.4+Sistema de compilacion
Kotlin1.9.22+Compatible con Java
Android API minima23 (Android 6.0)Dispositivos soportados
Android API objetivo33+ (Android 13+)Version recomendada
Hilt (Dagger)2.48Framework de inyeccion de dependencias

Requisitos Previos

Requisitos Técnicos

ComponenteVersión RequeridaNotas
Android StudioIguana o superiorIDE recomendado
Gradle8.4+Sistema de compilación
Kotlin1.9.22+Lenguaje de programación
Android API mínima22 (Android 5.1)Dispositivos soportados
Android API objetivo33+ (Android 13+)Versión recomendada
Java Compatibility18Nivel de compatibilidad

Credenciales Necesarias

1. Licencia del SDK (obligatorio)

Existen dos formas de obtener la licencia del SDK:

Opción A: Solicitud Directa

  • Formato: String alfanumérico único
  • Ejemplo: "ABC-123-XYZ-789"
  • Solicitar a: [email protected]

Opción B: Generación mediante API

Si no obtiene la licencia directamente del equipo JAAK, puede generarla mediante el siguiente proceso:

Paso 1: Obtener el Trace ID

Llamar al endpoint de inicio de flujo KYC:

POST /v1/kyc/session

De la respuesta, obtener el header traceparenty x-trace-id:

traceparent: 00-cf143715d7a2d4ffc3ef122f62384844-6f7048446dffdb89-00
x-trace-id :32922b9bf22570da5e9895fa592c6852

Paso 2: Validar la Licencia

Construir la licencia agregando el prefijo L al x-trace-id:

Lcf143715d7a2d4ffc3ef122f62384844

El campo obtenido se utilizará para autenticar los sdks y el campo traceparent debe de ser enviado en los headers de todos los llamados por api que se realicen .

2. Google Play Integrity API (obligatorio)

3. Permisos de Android (se configuran automáticamente)

  1. Permisos de Android (se configuran en AndroidManifest)
    • CAMERA (obligatorio)
    • WRITE_EXTERNAL_STORAGE (solo Android menor o igual a 9)

Instalacion

Paso 1: Configurar Repositorio Maven

Agregue el repositorio de JAAK en su archivo settings.gradle:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { 
            url "https://us-maven.pkg.dev/jaak-platform/jaak-android"
        }
    }
}

Paso 2: Agregar Dependencia del SDK

En su archivo build.gradle (modulo app):

dependencies {
    // JAAK Stamps SDK
    implementation 'com.jaak.stampssdk:jaakstamps-sdk:1.2.3'
    
    // Dependencias requeridas
    implementation "com.google.dagger:hilt-android:2.48"
    kapt "com.google.dagger:hilt-android-compiler:2.48"
}

Paso 3: Configurar Plugins

En su build.gradle (modulo app):

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

Paso 4: Configurar Build.gradle del Proyecto

En su build.gradle (nivel proyecto):

buildscript {
    ext.kotlin_version = "1.9.22"
    ext.hilt_version = '2.48'
    dependencies {
        classpath 'com.android.tools.build:gradle:8.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
    }
}

Paso 5: Configurar Permisos

En su AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="tu.paquete.app">

    <!-- Permisos necesarios -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" 
        android:maxSdkVersion="28"/>
    
    <!-- Features requeridos -->
    <uses-feature android:name="android.hardware.camera" android:required="true" />
    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        ...>
        
        <!-- FileProvider para compartir archivos -->
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        
    </application>
</manifest>

Paso 6: Configurar FileProvider

El SDK utiliza FileProvider para compartir archivos de forma segura entre componentes. Cree el archivo res/xml/file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- For Pictures directory -->
    <external-path name="my_images" path="Pictures/" />

    <!-- For getExternalFilesDir() - required by Jaak Stamps SDK -->
    <external-files-path name="external_files" path="." />
    <external-files-path name="jaak_stamps" path="Jaak Stamps SDK/" />

    <!-- For internal files and cache -->
    <files-path name="internal_files" path="." />
    <cache-path name="cache" path="." />

    <!-- For external cache -->
    <external-cache-path name="external_cache" path="." />
</paths>

Configuracion Inicial

Inicializar el SDK

El SDK debe inicializarse UNA SOLA VEZ al inicio de su aplicacion:

import android.app.Application
import com.jaak.stampssdk.StampsSDK
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class MyApplication : Application() {
    
    override fun onCreate() {
        super.onCreate()
        
        // Inicializar el SDK con su licencia
        StampsSDK.initialize("SU-LICENCIA-AQUI")
    }
}

No olvide registrar su Application en el AndroidManifest.xml:

<application
    android:name=".MyApplication"
    ...>

Como Usar el SDK

Arquitectura Basica

El SDK funciona mediante un patron de callbacks. Su Activity o Fragment debe:

  1. Implementar la interfaz StampsListener
  2. Crear una instancia de StampsSDK
  3. Configurar los parametros deseados (opcional)
  4. Iniciar la captura con startStamps()
  5. Recibir los resultados en los callbacks

Implementacion en Activity

import com.jaak.stampssdk.StampsSDK
import com.jaak.stampssdk.interfaces.StampsListener
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), StampsListener {
    
    private lateinit var stampsSDK: StampsSDK
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Crear instancia del SDK
        stampsSDK = StampsSDK(this, this)
        
        // Configurar el SDK (opcional)
        configureSDK()
        
        // Boton para iniciar captura
        findViewById<Button>(R.id.btnCapture).setOnClickListener {
            startDocumentCapture()
        }
    }
    
    private fun configureSDK() {
        // Configuraciones opcionales
        stampsSDK.apply {
            setAlignmentTolerance(30)
            setMaskSize(80)
            setCropMargin(150)
            setCaptureDelay(1500)
            setShowPreview(true)
        }
    }
    
    private fun startDocumentCapture() {
        // Iniciar captura inteligente
        // typeProcess = 1 para captura automatica inteligente
        stampsSDK.startStamps(typeProcess = 1)
    }
    
    // Callbacks del SDK
    override fun onSuccessStamps(
        typeProcess: Int,
        frontOriginalUri: Uri?,
        frontCropUri: Uri?,
        backOriginalUri: Uri?,
        backCropUri: Uri?,
        frontFaceCropUri: Uri?
    ) {
        // Documento capturado exitosamente
        handleSuccessfulCapture(
            frontOriginalUri,
            frontCropUri,
            backOriginalUri,
            backCropUri,
            frontFaceCropUri
        )
    }
    
    override fun onErrorStamps(error: String) {
        // Error en la captura
        Log.e("StampsSDK", "Error: $error")
        showError(error)
    }
    
    private fun handleSuccessfulCapture(
        frontOriginal: Uri?,
        frontCrop: Uri?,
        backOriginal: Uri?,
        backCrop: Uri?,
        faceCrop: Uri?
    ) {
        // Determinar tipo de documento
        val documentType = when {
            backOriginal != null -> "INE/IFE (frente y reverso)"
            frontOriginal != null -> "Pasaporte (solo frente)"
            else -> "Desconocido"
        }
        
        Log.d("StampsSDK", "Tipo de documento: $documentType")
        
        // Procesar imagenes
        processDocument(frontCrop, backCrop, faceCrop)
    }
}

Parametros de Entrada

1. initialize(license: String)

Inicializa el SDK con la licencia proporcionada por JAAK.

Tipo: String

Descripcion:

  • Debe llamarse UNA SOLA VEZ al inicio de la aplicacion
  • Generalmente se llama en la clase Application
  • La licencia valida que la app tiene permiso para usar el SDK
  • Sin una licencia valida, el SDK no funcionara

Parametro license:

  • Formato: String alfanumerico con guiones
  • Ejemplo: "ABCD-1234-EFGH-5678"
  • Longitud tipica: 19 caracteres
  • Sensible a mayusculas/minusculas

Ejemplo:

@HiltAndroidApp
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        StampsSDK.initialize("ABCD-1234-EFGH-5678")
    }
}

Como obtener licencia:

  1. Enviar email a: [email protected]
  2. Proporcionar: nombre de empresa, package name de app
  3. Licencias de desarrollo son gratuitas
  4. Licencias de produccion tienen costo segun volumen

Importante:

  • NO incluir la licencia directamente en el codigo versionado
  • Usar BuildConfig o archivo de configuracion:
// En build.gradle
buildConfigField("String", "STAMPS_LICENSE", "\"${project.findProperty("stamps.license")}\"")

// En local.properties
stamps.license=ABCD-1234-EFGH-5678

// En codigo
StampsSDK.initialize(BuildConfig.STAMPS_LICENSE)

2. StampsSDK(activity: AppCompatActivity, listener: StampsListener)

Constructor que crea una instancia del SDK para una Activity especifica.

Parametros:

ParametroTipoObligatorioDescripcion
activityAppCompatActivitySiActivity desde donde se inicia el SDK
listenerStampsListenerSiInterfaz para recibir callbacks

Descripcion:

Parametro activity:

  • La Activity debe estar anotada con @AndroidEntryPoint si usa Hilt
  • El SDK necesita el contexto de la Activity para:
    • Solicitar permisos de camara
    • Iniciar la Activity de captura
    • Gestionar el ciclo de vida
  • Debe ser la Activity desde donde se llama startStamps()

Parametro listener:

  • Debe ser una clase que implemente StampsListener
  • Generalmente la misma Activity implementa esta interfaz
  • Recibe los callbacks con resultados y errores

Ejemplo:

@AndroidEntryPoint
class CaptureActivity : AppCompatActivity(), StampsListener {
    
    private lateinit var stampsSDK: StampsSDK
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Crear instancia pasando this como Activity y Listener
        stampsSDK = StampsSDK(
            activity = this,  // Esta Activity
            listener = this   // Esta Activity implementa StampsListener
        )
    }
    
    override fun onSuccessStamps(...) { }
    override fun onErrorStamps(error: String) { }
}

Ciclo de vida:

  • Cada Activity debe tener su propia instancia de StampsSDK
  • El SDK gestiona automaticamente los cambios de configuracion
  • No es necesario liberar recursos manualmente

3. startStamps(typeProcess: Int)

Inicia el proceso de captura de documentos.

Tipo: Int

Valores posibles:

ValorNombreDescripcionCuando usar
1Captura InteligenteEl SDK detecta automaticamente el tipo de documento y captura frente y/o reverso segun sea necesarioRecomendado - La mayoria de casos
2Solo FrenteCaptura unicamente el frente del documentoCuando sabes que es pasaporte o documento sin reverso
3Frente y ReversoCaptura obligatoriamente frente y reversoCuando sabes que es INE/IFE/Cedula

Valor por defecto: No tiene valor por defecto, debe especificarse

Descripcion detallada:

typeProcess = 1 (Captura Inteligente) - RECOMENDADO

El modo mas comun e inteligente:

  • El SDK analiza el documento capturado
  • Determina automaticamente si tiene reverso
  • Para documentos con reverso (INE, IFE):
    • Captura el frente
    • Automaticamente pide capturar el reverso
    • Retorna ambas imagenes
  • Para documentos sin reverso (Pasaporte):
    • Captura solo el frente
    • Retorna solo imagenes del frente
    • backOriginalUri y backCropUri seran null

Ventajas:

  • No necesitas saber que tipo de documento es
  • Experiencia de usuario mas fluida
  • Reduce errores (no pide reverso de pasaportes)

Desventajas:

  • Ninguna significativa

typeProcess = 2 (Solo Frente)

Captura unicamente el frente del documento:

  • Solo hace una captura
  • No pide el reverso aunque el documento lo tenga
  • Util cuando solo necesitas la foto del documento

Cuando usar:

  • Sabes con certeza que es un pasaporte
  • Solo necesitas la foto del frente para validacion rapida
  • Registro simplificado donde no necesitas datos del reverso
  • Casos donde el reverso no agrega valor

Retorna:

  • frontOriginalUri - Foto completa del frente
  • frontCropUri - Documento recortado
  • frontFaceCropUri - Rostro extraido (si disponible)
  • backOriginalUri - Siempre null
  • backCropUri - Siempre null

typeProcess = 3 (Frente y Reverso)

Captura obligatoriamente frente y reverso:

  • Siempre pide dos capturas
  • Incluso si es un pasaporte (que no tiene reverso)
  • Util cuando SABES que necesitas ambos lados

Cuando usar:

  • Estas 100% seguro que es INE/IFE/Cedula
  • Tu proceso REQUIERE ambos lados siempre
  • Validacion completa de documentos con reverso

Retorna:

  • frontOriginalUri - Foto completa del frente
  • frontCropUri - Documento recortado (frente)
  • backOriginalUri - Foto completa del reverso
  • backCropUri - Documento recortado (reverso)
  • frontFaceCropUri - Rostro extraido (si disponible)

Ejemplo:

// Modo recomendado - Captura inteligente
stampsSDK.startStamps(1)  // Mejor para la mayoria de casos

// Solo frente - para pasaportes o registro rapido
stampsSDK.startStamps(2)  // Cuando solo necesitas el frente

// Frente y reverso obligatorio - para INE/IFE
stampsSDK.startStamps(3)  // Cuando necesitas ambos lados

Cual usar:

Tu caso de usotypeProcess recomendado
No sabes que documento subira el usuario1 (Inteligente)
Onboarding general de usuarios1 (Inteligente)
Verificacion KYC completa1 (Inteligente)
Solo aceptas pasaportes2 (Solo frente)
Registro rapido sin validacion exhaustiva2 (Solo frente)
Solo aceptas INE/IFE mexicana3 (Frente y reverso)
Necesitas datos del reverso siempre3 (Frente y reverso)

4. setAlignmentTolerance(tolerance: Int)

Configura que tan estricto es el SDK al validar la alineacion del documento.

Tipo: Int

Rango valido: 0 - 100

Valor por defecto: 30

Descripcion:

Este parametro controla que tan perfectamente alineado debe estar el documento para ser capturado:

  • Valor bajo (0-20):

    • Muy estricto
    • Requiere alineacion casi perfecta
    • Mejor calidad de imagen
    • Usuario tarda mas en capturar
    • Recomendado para: aplicaciones financieras, KYC regulado
  • Valor medio (20-40):

    • Balance entre calidad y facilidad
    • Alineacion razonable requerida
    • Buena calidad de imagen
    • Tiempo de captura moderado
    • Recomendado para: la mayoria de aplicaciones
  • Valor alto (40-100):

    • Muy tolerante
    • Acepta documentos con ligera inclinacion
    • Captura mas rapida
    • Calidad puede variar mas
    • Recomendado para: dispositivos de gama baja, usuarios con dificultades motoras

Ejemplo:

// Maxima calidad (fintech, bancos)
stampsSDK.setAlignmentTolerance(15)

// Balance calidad/facilidad (recomendado)
stampsSDK.setAlignmentTolerance(30)

// Facilidad de uso (apps masivas)
stampsSDK.setAlignmentTolerance(45)

// Muy permisivo (gama baja)
stampsSDK.setAlignmentTolerance(60)

5. setMaskSize(size: Int)

Configura el tamano del area de deteccion del documento en pantalla.

Tipo: Int

Rango valido: 50 - 100

Valor por defecto: 80

Descripcion:

Este parametro define que tan grande es el marco/mascara que aparece en pantalla para guiar al usuario:

  • Valor bajo (50-65):

    • Marco pequeno en pantalla
    • Usuario debe acercar mas la camara
    • Mejor para pantallas pequenas
    • Mas procesamiento (area menor)
    • Recomendado para: dispositivos de gama baja, pantallas menores a 5"
  • Valor medio (65-85):

    • Marco de tamano moderado
    • Balance entre facilidad y rendimiento
    • Comodo para la mayoria de usuarios
    • Recomendado para: la mayoria de aplicaciones
  • Valor alto (85-100):

    • Marco grande en pantalla
    • Usuario puede estar mas alejado
    • Mas facil de usar
    • Requiere mas procesamiento
    • Recomendado para: tablets, pantallas mayores a 6", usuarios con dificultades visuales

Impacto en la experiencia:

Tamano del MarcoDistancia optimaDificultadRendimiento
50-65 (pequeno)15-20 cmAltaExcelente
65-80 (medio)20-30 cmMediaBueno
80-95 (grande)30-40 cmBajaModerado
95-100 (muy grande)40+ cmMuy bajaPuede ser lento en gama baja

Ejemplo:

// Pantalla pequena / gama baja
stampsSDK.setMaskSize(65)

// Tamano estandar (recomendado)
stampsSDK.setMaskSize(80)

// Pantalla grande / facilidad maxima
stampsSDK.setMaskSize(90)

Recomendacion por tipo de dispositivo:

Tipo de dispositivoValor recomendado
Gama baja (menor a 2GB RAM)60-70
Gama media (2-4GB RAM)75-85
Gama alta (mayor a 4GB RAM)80-95
Tablets85-95

6. setCropMargin(margin: Int)

Configura el margen adicional que se incluye al recortar el documento.

Tipo: Int

Rango valido: 0 - 170

Valor por defecto: 150

Descripcion:

Este parametro controla cuanto contexto adicional se incluye alrededor del documento en la imagen recortada:

  • Valor bajo (0-100):

    • Recorte muy ajustado al documento
    • Imagen mas pequena (menos MB)
    • Puede cortar bordes si la deteccion no es perfecta
    • Riesgo de perder informacion de los bordes
    • Recomendado solo si el espacio es critico
  • Valor medio (100-160):

    • Balance entre precision y contexto
    • Incluye bordes completos del documento
    • Tamano de archivo razonable
    • Seguro para procesamiento OCR
    • Recomendado para: la mayoria de aplicaciones
  • Valor alto (160-170):

    • Incluye mucho contexto alrededor
    • Garantiza captura de todos los bordes
    • Archivos mas grandes
    • Util para validacion visual manual
    • Recomendado para: aplicaciones de archivo documental

Ejemplo:

// Recorte ajustado (ahorro de espacio)
stampsSDK.setCropMargin(100)

// Recorte estandar (recomendado)
stampsSDK.setCropMargin(150)

// Recorte amplio (archivo documental)
stampsSDK.setCropMargin(170)

Recomendacion por caso de uso:

Caso de usoValor recomendadoJustificacion
OCR automatico130-150Garantiza captura de todos los campos
Validacion visual150-170Incluye contexto para revision humana
Almacenamiento limitado100-120Reduce tamano de archivos
Archivo legal160-170Maximo contexto para evidencia
Procesamiento AI140-160Balance entre contexto y tamano

7. setCaptureDelay(milliseconds: Int)

Configura el tiempo de espera antes de capturar automaticamente.

Tipo: Int (milisegundos)

Rango valido: 500 - 5000

Valor por defecto: 1500 (1.5 segundos)

Descripcion:

Este parametro define cuanto tiempo debe mantener el usuario el documento correctamente posicionado antes de que el SDK capture automaticamente:

  • Valor bajo (500-1000ms):

    • Captura muy rapida
    • Menos tiempo de espera para el usuario
    • Mayor riesgo de capturar imagen borrosa (movimiento)
    • Recomendado para: usuarios expertos, dispositivos de gama alta
  • Valor medio (1000-2000ms):

    • Balance entre velocidad y estabilidad
    • Tiempo suficiente para estabilizar
    • Experiencia fluida
    • Recomendado para: la mayoria de aplicaciones
  • Valor alto (2000-5000ms):

    • Captura muy estable
    • Usuario tiene mucho tiempo para posicionar
    • Puede sentirse lento
    • Garantiza mejor calidad
    • Recomendado para: gama baja, usuarios con dificultades motoras

Impacto en la experiencia:

DelayExperiencia del usuarioCalidad esperadaMejor para
500-800msMuy rapida, puede sorprenderVariableUsuarios expertos
1000-1500msFluida y naturalBuenaUsuarios generales
1500-2500msComoda, no apuradaMuy buenaPrimera vez usuarios
2500-5000msLenta, puede frustrarExcelenteCasos especiales

Ejemplo:

// Captura rapida (usuarios expertos)
stampsSDK.setCaptureDelay(1000)

// Captura estandar (recomendado)
stampsSDK.setCaptureDelay(1500)

// Captura con pausa (maxima estabilidad)
stampsSDK.setCaptureDelay(2500)

Recomendacion por contexto:

ContextoValor recomendadoJustificacion
Primera captura del usuario2000-2500msDale tiempo para entender
Usuario experimentado1000-1500msYa sabe que hacer
Dispositivo de gama alta1000-1500msProcesa rapido y estable
Dispositivo de gama baja1500-2000msNecesita mas tiempo para procesar
Entorno con movimiento2000-3000msEsperar momento de estabilidad
Punto de venta rapido1000-1200msVelocidad es prioridad

Combinacion con otros parametros:

// Configuracion RAPIDA (punto de venta)
stampsSDK.apply {
    setCaptureDelay(1000)        // Captura rapida
    setAlignmentTolerance(40)    // Mas tolerante
    setShowPreview(false)        // Sin preview, mas directo
}

// Configuracion PRECISA (banca/finanzas)
stampsSDK.apply {
    setCaptureDelay(2000)        // Captura estable
    setAlignmentTolerance(20)    // Muy estricto
    setShowPreview(true)         // Permitir revision
}

// Configuracion BALANCED (recomendada)
stampsSDK.apply {
    setCaptureDelay(1500)        // Balance
    setAlignmentTolerance(30)    // Balance
    setShowPreview(true)         // Incluir preview
}

8. setShowPreview(enabled: Boolean)

Configura si se muestra una pantalla de vista previa despues de cada captura.

Tipo: Boolean

Valores posibles:

  • true - Muestra preview, usuario puede aceptar o reintentar
  • false - Sin preview, captura directa

Valor por defecto: true

Descripcion:

Este parametro controla el flujo de experiencia del usuario despues de cada captura:

Cuando enabled = true (Con Preview) - RECOMENDADO

Despues de capturar cada imagen:

  1. SDK muestra la imagen capturada en pantalla
  2. Usuario ve dos botones:
    • Aceptar/Continuar - Confirma que la imagen es buena
    • Reintentar - Vuelve a capturar si no esta satisfecho
  3. Si aceptan: continua al siguiente paso o termina
  4. Si reintenta: vuelve a la camara para nueva captura

Ventajas:

  • Usuario tiene control y confianza
  • Puede corregir capturas borrosas o mal iluminadas
  • Reduce reintentos completos del proceso
  • Mejor experiencia de usuario

Desventajas:

  • Proceso un poco mas largo
  • Requiere un tap adicional por captura

Cuando usar:

  • Verificacion de identidad (KYC)
  • Onboarding de usuarios
  • Aplicaciones donde la calidad es critica
  • Primera vez que el usuario usa la app
  • Cuando el usuario es el dueno del documento

Cuando enabled = false (Sin Preview) - FLUJO RAPIDO

Despues de capturar cada imagen:

  1. SDK captura y procesa automaticamente
  2. No muestra la imagen al usuario
  3. Pasa directamente al siguiente paso o termina
  4. Proceso completamente automatico

Ventajas:

  • Proceso muy rapido
  • Menos interacciones requeridas
  • Ideal para alto volumen de capturas
  • Experiencia mas fluida

Desventajas:

  • Usuario no puede validar calidad antes de enviar
  • Si la imagen es mala, debe repetir todo el proceso
  • Menos control para el usuario

Cuando usar:

  • Puntos de venta rapidos
  • Procesos donde un operador captura (no el dueno del documento)
  • Alto volumen de transacciones
  • Cuando el tiempo es critico
  • Usuarios expertos que repiten el proceso frecuentemente

Ejemplo:

// Con preview (recomendado para la mayoria)
stampsSDK.setShowPreview(true)

// Sin preview (flujo rapido)
stampsSDK.setShowPreview(false)

Comparacion de flujos:

CON PREVIEW (true):

1. Usuario posiciona documento
2. SDK captura automaticamente
3. [PANTALLA DE PREVIEW]
4. Usuario ve la imagen
5. Usuario decide: Aceptar o Reintentar?
   - Aceptar -> Continuar
   - Reintentar -> Volver a paso 1

SIN PREVIEW (false):

1. Usuario posiciona documento
2. SDK captura automaticamente
3. Procesa y continua inmediatamente

9. setShowDebugMode(enabled: Boolean)

Activa o desactiva el modo de depuracion con logs detallados.

Tipo: Boolean

Valores posibles:

  • true - Activa logs detallados en Logcat
  • false - Logs minimos (solo errores)

Valor por defecto: false

Descripcion:

Cuando esta activado, el SDK genera logs detallados sobre:

  • Inicializacion del SDK
  • Validacion de licencia
  • Proceso de captura (deteccion, alineacion, calidad)
  • Recorte de imagenes
  • Extraccion de rostro
  • Guardado de archivos
  • Errores y warnings

Cuando activarlo:

  • Durante desarrollo
  • Al integrar el SDK por primera vez
  • Al debuggear problemas
  • Cuando contactes a soporte tecnico
  • NO en produccion (impacto en rendimiento)

Ejemplo:

// Activar en desarrollo
if (BuildConfig.DEBUG) {
    stampsSDK.setShowDebugMode(true)
}

// Desactivar en produccion
if (!BuildConfig.DEBUG) {
    stampsSDK.setShowDebugMode(false)
}

Logs tipicos que veras:

D/StampsSDK: Initializing SDK with license: XXXX-****-****-XXXX
D/StampsSDK: License validated successfully
D/StampsSDK: Starting capture with typeProcess: 1
D/StampsSDK: Document detected in frame
D/StampsSDK: Alignment: 85% (tolerance: 30%)
D/StampsSDK: Quality check: brightness=OK, sharpness=OK, size=OK
D/StampsSDK: Auto-capture in 1500ms
D/StampsSDK: Image captured successfully
D/StampsSDK: Cropping document with margin: 150
D/StampsSDK: Extracting face from document
D/StampsSDK: Face detected and extracted
D/StampsSDK: Analyzing document type: INE detected
D/StampsSDK: Requesting back side capture
D/StampsSDK: Process completed successfully

Importante:

  • Los logs pueden contener informacion sensible
  • No dejar activado en produccion
  • Revisar logs antes de enviar a soporte (remover datos sensibles)

10. setSecurityValidationEnabled(enabled: Boolean)

Activa validaciones de seguridad adicionales contra emuladores y camaras virtuales.

Tipo: Boolean

Valores posibles:

  • true - Activa validaciones de seguridad
  • false - Sin validaciones adicionales

Valor por defecto: false

Descripcion:

Cuando esta activado, el SDK realiza validaciones adicionales para:

  • Detectar si esta corriendo en un emulador
  • Verificar si la camara es virtual/simulada
  • Validar que el dispositivo es autentico
  • Prevenir ataques de spoofing basicos

Cuando activarlo:

IndustriaRecomendacionJustificacion
Banca/FinanzasActivarAlto riesgo de fraude
SegurosActivarValidacion critica
FintechActivarRegulaciones KYC
E-commerceConsiderarSegun nivel de riesgo
Apps de DeliveryNo necesarioBajo riesgo de fraude
Registro generalNo necesarioValidacion basica suficiente

Impacto:

  • Mayor seguridad
  • Previene fraudes basicos
  • Puede rechazar algunos dispositivos legitimos en casos edge
  • Ligero impacto en rendimiento

Ejemplo:

// Para aplicaciones financieras
stampsSDK.setSecurityValidationEnabled(true)

// Para aplicaciones de uso general
stampsSDK.setSecurityValidationEnabled(false)

Validaciones que realiza:

  1. Deteccion de emulador:

    • Verifica propiedades del dispositivo
    • Detecta emuladores comunes (Android Studio, Genymotion, etc.)
  2. Validacion de camara:

    • Verifica que la camara sea hardware real
    • Detecta camaras virtuales o simuladas
  3. Integridad del dispositivo:

    • Valida que el dispositivo no esta rooteado (opcional)
    • Verifica firma de la aplicacion

Que pasa si detecta problema:

  • El callback onErrorStamps() se invoca
  • Error tipo: "security_validation_failed"
  • Mensaje descriptivo del problema detectado

Importante:

  • No es una solucion de seguridad completa
  • Para maxima seguridad, validar tambien en tu backend
  • Complementar con otras medidas de seguridad
  • Puede generar falsos positivos en dispositivos modificados legitimamente

Parametros de Salida

Interface: StampsListener

Su Activity o Fragment debe implementar esta interfaz para recibir los resultados del SDK.

interface StampsListener {
    fun onSuccessStamps(
        typeProcess: Int,
        frontOriginalUri: Uri?,
        frontCropUri: Uri?,
        backOriginalUri: Uri?,
        backCropUri: Uri?,
        frontFaceCropUri: Uri?
    )
    
    fun onErrorStamps(error: String)
}

1. onSuccessStamps(...) - Callback de Exito

Se invoca cuando el SDK completa exitosamente la captura del documento.

Cuando se invoca:

  • Despues de capturar todas las imagenes requeridas (frente y/o reverso)
  • Despues de que el usuario confirme en el preview (si esta activado)
  • Cuando todas las imagenes han sido procesadas y guardadas

Parametros:

typeProcess: Int

Devuelve el mismo valor de typeProcess que se paso a startStamps().

Tipo: Int

Valores posibles: 1, 2, o 3

Uso: Permite identificar que modo de captura se uso, util si manejas multiples flujos.

Ejemplo:

override fun onSuccessStamps(
    typeProcess: Int,
    ...
) {
    when (typeProcess) {
        1 -> Log.d("Stamps", "Captura inteligente completada")
        2 -> Log.d("Stamps", "Solo frente capturado")
        3 -> Log.d("Stamps", "Frente y reverso capturados")
    }
}

frontOriginalUri: Uri?

URI de la imagen original del frente del documento (sin recortar).

Tipo: Uri? (puede ser null)

Cuando es null:

  • Nunca deberia ser null si el callback se ejecuta exitosamente
  • Si es null, hubo un error en el guardado del archivo

Descripcion:

  • Imagen completa tal como fue capturada por la camara
  • Incluye todo el encuadre: documento + fondo
  • Resolucion completa de la camara
  • Sin procesamiento ni recortes
  • Util para auditoria o validacion manual

Caracteristicas tipicas:

  • Formato: JPEG
  • Resolucion: Segun camara del dispositivo (tipicamente 2-12 MP)
  • Tamano de archivo: 1-5 MB
  • Ubicacion: Almacenamiento interno de la app

Cuando usar esta imagen:

  • Archivo documental completo
  • Necesitas contexto alrededor del documento
  • Validacion manual humana
  • Backup/auditoria
  • Cuando la calidad del recorte no es optima

Ejemplo:

override fun onSuccessStamps(..., frontOriginalUri: Uri?, ...) {
    frontOriginalUri?.let { uri ->
        // Guardar para auditoria
        saveToBackup(uri)
        
        // Mostrar en ImageView
        binding.imageOriginal.setImageURI(uri)
        
        // Convertir a Base64
        val base64 = Utils.uriToBase64(contentResolver, uri)
    }
}

frontCropUri: Uri?

URI de la imagen del frente del documento recortada y optimizada.

Tipo: Uri? (puede ser null)

Cuando es null:

  • Solo si hubo error en el proceso de recorte
  • Muy raro, generalmente siempre esta presente

Descripcion:

  • Documento recortado eliminando el fondo
  • Solo contiene el documento y un margen configurable
  • Optimizada para procesamiento (OCR, validacion)
  • Mejor calidad visual
  • Esta es la imagen que DEBES usar para procesamiento

Caracteristicas tipicas:

  • Formato: JPEG
  • Resolucion: Optimizada (tipicamente 1200-2000px de ancho)
  • Tamano de archivo: 200-800 KB
  • Orientacion: Siempre horizontal (el SDK rota automaticamente)
  • Ubicacion: Almacenamiento interno de la app

Procesamiento aplicado:

  • Recorte inteligente del documento
  • Correccion de perspectiva (si estaba inclinado)
  • Mejora de contraste
  • Reduccion de ruido
  • Rotacion a orientacion correcta

Cuando usar esta imagen:

  • OCR (extraccion de datos)
  • Validacion automatica del documento
  • Envio a APIs de verificacion
  • Machine Learning / IA
  • Comparacion con base de datos
  • Procesamiento en general

Ejemplo:

override fun onSuccessStamps(..., frontCropUri: Uri?, ...) {
    frontCropUri?.let { uri ->
        // Convertir a Base64 para API
        val base64 = Utils.uriToBase64(contentResolver, uri)
        
        // Enviar a servicio de OCR
        ocrService.extractData(base64)
        
        // Enviar a API de validacion
        apiService.validateDocument(base64)
        
        // Mostrar en UI
        binding.imageDocument.setImageURI(uri)
    }
}

backOriginalUri: Uri?

URI de la imagen original del reverso del documento (sin recortar).

Tipo: Uri? (puede ser null)

Cuando es null:

  • Cuando el documento NO tiene reverso (ej: Pasaporte)
  • Cuando se uso startStamps(2) (solo frente)
  • En captura inteligente, si detecto que es documento sin reverso

Cuando tiene valor:

  • Cuando el documento tiene reverso (INE, IFE, Cedula)
  • Cuando se uso startStamps(3) (frente y reverso obligatorio)
  • En captura inteligente, si detecto documento con reverso

Descripcion:

  • Imagen completa del reverso tal como fue capturada
  • Incluye documento + fondo
  • Resolucion completa de la camara
  • Sin procesamiento ni recortes

Uso: Similar a frontOriginalUri pero para el reverso

Ejemplo:

override fun onSuccessStamps(
    ...,
    backOriginalUri: Uri?,
    ...
) {
    if (backOriginalUri != null) {
        // Documento tiene reverso (INE/IFE/Cedula)
        Log.d("Stamps", "Documento con reverso capturado")
        saveBackOriginal(backOriginalUri)
    } else {
        // Documento sin reverso (Pasaporte) o solo capturo frente
        Log.d("Stamps", "Documento sin reverso o solo frente capturado")
    }
}

backCropUri: Uri?

URI de la imagen del reverso del documento recortada y optimizada.

Tipo: Uri? (puede ser null)

Cuando es null:

  • Cuando el documento NO tiene reverso (ej: Pasaporte)
  • Cuando se uso startStamps(2) (solo frente)
  • En captura inteligente, si detecto que es documento sin reverso

Cuando tiene valor:

  • Cuando el documento tiene reverso
  • Cuando se capturaron ambos lados

Descripcion:

  • Reverso del documento recortado y optimizado
  • Solo contiene el documento con margen configurable
  • Procesamiento identico a frontCropUri
  • Usar esta imagen para procesar datos del reverso

Uso: Similar a frontCropUri pero para el reverso

Datos comunes en el reverso:

  • INE/IFE: Domicilio, CURP, CIC, fecha de registro, codigo de barras
  • Licencia: Restricciones, tipo de licencia, vigencia
  • Cedula: Informacion adicional segun el pais

Ejemplo:

override fun onSuccessStamps(
    ...,
    backCropUri: Uri?,
    ...
) {
    backCropUri?.let { uri ->
        // Convertir a Base64
        val base64Back = Utils.uriToBase64(contentResolver, uri)
        
        // Extraer datos del reverso
        ocrService.extractBackData(base64Back) // CURP, domicilio, etc.
        
        // Validar codigo de barras/QR si existe
        barcodeService.validateQRCode(base64Back)
    }
}

frontFaceCropUri: Uri?

URI de la foto del rostro extraida automaticamente del frente del documento.

Tipo: Uri? (puede ser null)

Cuando es null:

  • Cuando el documento NO contiene foto (raro, la mayoria tienen)
  • Cuando el SDK no pudo detectar/extraer el rostro
  • En documentos muy antiguos o deteriorados
  • Si la foto en el documento esta muy borrosa

Cuando tiene valor:

  • Cuando el documento tiene foto del titular (mayoria de casos)
  • INE, IFE, Pasaportes, Licencias, Cedulas

Descripcion:

  • Foto del rostro extraida automaticamente del documento
  • Recortada precisamente alrededor del rostro
  • Optimizada para comparacion facial (face matching)
  • Sin fondo ni elementos del documento
  • Resolucion adecuada para procesamiento biometrico

Caracteristicas tipicas:

  • Formato: JPEG
  • Resolucion: 200x250 px aproximadamente (varia segun documento)
  • Tamano de archivo: 10-50 KB
  • Solo contiene el rostro
  • Puede incluir parte del fondo de la foto original del documento

Cuando usar esta imagen:

  • Comparacion facial (face matching) con selfie
  • Verificacion biometrica
  • Validacion de identidad
  • Sistemas de reconocimiento facial
  • Analisis de liveness (prueba de vida)
  • Onboarding con verificacion facial

Ejemplo de uso completo:

override fun onSuccessStamps(
    typeProcess: Int,
    frontOriginalUri: Uri?,
    frontCropUri: Uri?,
    backOriginalUri: Uri?,
    backCropUri: Uri?,
    frontFaceCropUri: Uri?
) {
    // 1. Validar que tenemos las imagenes necesarias
    if (frontCropUri == null) {
        showError("No se pudo capturar el frente del documento")
        return
    }
    
    // 2. Determinar tipo de documento
    val documentType = when {
        backCropUri != null -> "INE/IFE"
        frontCropUri != null && backCropUri == null -> "Pasaporte"
        else -> "Desconocido"
    }
    
    Log.d("Stamps", "Tipo de documento: $documentType")
    
    // 3. Procesar imagen del frente (OCR)
    val frontBase64 = Utils.uriToBase64(contentResolver, frontCropUri)
    extractFrontData(frontBase64)
    
    // 4. Procesar reverso si existe
    backCropUri?.let { uri ->
        val backBase64 = Utils.uriToBase64(contentResolver, uri)
        extractBackData(backBase64)
    }
    
    // 5. Procesar rostro si existe
    frontFaceCropUri?.let { uri ->
        val faceBase64 = Utils.uriToBase64(contentResolver, uri)
        
        // Guardar para comparacion posterior con selfie
        saveFaceForComparison(faceBase64)
        
        // O hacer comparacion inmediata si ya tienes selfie
        val selfieBase64 = getUserSelfie()
        if (selfieBase64 != null) {
            compareFaces(faceBase64, selfieBase64)
        }
    } ?: run {
        Log.w("Stamps", "No se pudo extraer rostro del documento")
        // Continuar sin comparacion facial o pedir selfie manual
    }
    
    // 6. Guardar todo para auditoria
    saveDocumentCapture(
        frontOriginal = frontOriginalUri,
        frontCrop = frontCropUri,
        backOriginal = backOriginalUri,
        backCrop = backCropUri,
        face = frontFaceCropUri,
        documentType = documentType,
        timestamp = System.currentTimeMillis()
    )
    
    // 7. Continuar con el flujo
    navigateToNextStep()
}

private fun extractFrontData(base64: String) {
    // Extraer: nombre, apellidos, fecha nacimiento, etc.
    ocrService.extractFrontData(base64) { data ->
        // Procesar datos extraidos
        Log.d("OCR", "Nombre: ${data.name}")
        Log.d("OCR", "Fecha nacimiento: ${data.birthDate}")
    }
}

private fun extractBackData(base64: String) {
    // Extraer: CURP, domicilio, CIC, etc.
    ocrService.extractBackData(base64) { data ->
        Log.d("OCR", "CURP: ${data.curp}")
        Log.d("OCR", "Domicilio: ${data.address}")
    }
}

private fun compareFaces(documentFace: String, selfieFace: String) {
    faceMatchService.compare(documentFace, selfieFace) { result ->
        if (result.isMatch && result.confidence > 0.85) {
            Log.d("FaceMatch", "Rostros coinciden: ${result.confidence}")
            approveIdentityVerification()
        } else {
            Log.w("FaceMatch", "Rostros no coinciden: ${result.confidence}")
            requestManualReview()
        }
    }
}

Resumen de imagenes recibidas:

URIContieneCuando es nullUsar para
frontOriginalUriFrente completo sin recortarNuncaAuditoria, backup
frontCropUriFrente recortado y optimizadoNuncaOCR, validacion, procesamiento
backOriginalUriReverso completo sin recortarSi no tiene reversoAuditoria, backup
backCropUriReverso recortado y optimizadoSi no tiene reversoOCR reverso, datos adicionales
frontFaceCropUriRostro extraidoSi no tiene foto o no se detectoFace matching, biometria

2. onErrorStamps(error: String) - Callback de Error

Se invoca cuando ocurre un error durante el proceso de captura.

Cuando se invoca:

  • Error al inicializar la camara
  • Permisos de camara denegados
  • Error al guardar las imagenes
  • Licencia invalida
  • Error de procesamiento
  • Usuario cancela el proceso (en algunas implementaciones)

Parametro error:

Tipo: String

Descripcion: Mensaje descriptivo del error que ocurrio

Errores comunes:

Mensaje de ErrorCausaSolucion
"Camera permission denied"Usuario denego permiso de camaraSolicitar permiso nuevamente, explicar por que es necesario
"Camera not available"Camara en uso o no existeVerificar que el dispositivo tenga camara, cerrar otras apps que la usen
"License invalid"Licencia incorrecta o expiradaVerificar licencia, contactar [email protected]
"Failed to save image"Error al guardar archivoVerificar espacio de almacenamiento, permisos de escritura
"Document detection failed"No se pudo detectar documento en timeoutMejorar iluminacion, usar fondo contrastante
"Image processing error"Error al procesar/recortar imagenReintentar captura, puede ser problema temporal
"Security validation failed"Dispositivo no paso validaciones de seguridadDispositivo puede ser emulador o tener camara virtual
"User cancelled"Usuario cancelo el procesoNormal, permitir reintentar
"Low memory"Dispositivo sin memoria suficienteCerrar apps en background, liberar memoria
"Network error"Error de red (si SDK requiere internet)Verificar conectividad

Ejemplo de manejo completo:

override fun onErrorStamps(error: String) {
    Log.e("StampsSDK", "Error: $error")
    
    when {
        error.contains("permission", ignoreCase = true) -> {
            // Error de permisos
            handlePermissionError()
        }
        error.contains("camera not available", ignoreCase = true) -> {
            // Camara no disponible
            handleCameraUnavailable()
        }
        error.contains("license", ignoreCase = true) -> {
            // Problema con licencia
            handleLicenseError()
        }
        error.contains("failed to save", ignoreCase = true) -> {
            // Error al guardar
            handleSaveError()
        }
        error.contains("cancelled", ignoreCase = true) -> {
            // Usuario cancelo
            handleUserCancellation()
        }
        error.contains("security", ignoreCase = true) -> {
            // Problema de seguridad
            handleSecurityError()
        }
        error.contains("memory", ignoreCase = true) -> {
            // Memoria baja
            handleLowMemory()
        }
        else -> {
            // Error generico
            handleGenericError(error)
        }
    }
}

private fun handlePermissionError() {
    AlertDialog.Builder(this)
        .setTitle("Permiso necesario")
        .setMessage("Necesitamos acceso a la camara para capturar tu documento de identidad.")
        .setPositiveButton("Permitir") { _, _ ->
            requestCameraPermission()
        }
        .setNegativeButton("Cancelar") { dialog, _ ->
            dialog.dismiss()
            finish()
        }
        .show()
}

private fun handleCameraUnavailable() {
    AlertDialog.Builder(this)
        .setTitle("Camara no disponible")
        .setMessage("No pudimos acceder a la camara. Asegurate de que ninguna otra aplicacion la este usando.")
        .setPositiveButton("Reintentar") { _, _ ->
            stampsSDK.startStamps(1)
        }
        .setNegativeButton("Cancelar") { dialog, _ ->
            dialog.dismiss()
        }
        .show()
}

private fun handleLicenseError() {
    AlertDialog.Builder(this)
        .setTitle("Error de configuracion")
        .setMessage("Hubo un problema con la configuracion de la aplicacion. Por favor contacta a soporte.")
        .setPositiveButton("Entendido") { dialog, _ ->
            dialog.dismiss()
            // Registrar error para analisis
            logCriticalError("License validation failed")
            // Opcionalmente cerrar la app
            finish()
        }
        .setCancelable(false)
        .show()
}

private fun handleSaveError() {
    AlertDialog.Builder(this)
        .setTitle("Error al guardar")
        .setMessage("No pudimos guardar las imagenes capturadas. Verifica que tengas espacio disponible.")
        .setPositiveButton("Reintentar") { _, _ ->
            stampsSDK.startStamps(1)
        }
        .setNegativeButton("Cancelar") { dialog, _ ->
            dialog.dismiss()
        }
        .show()
}

private fun handleUserCancellation() {
    // Usuario cancelo, comportamiento normal
    AlertDialog.Builder(this)
        .setTitle("Captura cancelada")
        .setMessage("Deseas intentar nuevamente?")
        .setPositiveButton("Si") { _, _ ->
            stampsSDK.startStamps(1)
        }
        .setNegativeButton("No") { dialog, _ ->
            dialog.dismiss()
            finish()
        }
        .show()
}

private fun handleSecurityError() {
    AlertDialog.Builder(this)
        .setTitle("Validacion de seguridad fallida")
        .setMessage("Tu dispositivo no paso las validaciones de seguridad. Esto puede ocurrir en emuladores o dispositivos modificados.")
        .setPositiveButton("Entendido") { dialog, _ ->
            dialog.dismiss()
            finish()
        }
        .setCancelable(false)
        .show()
}

private fun handleLowMemory() {
    AlertDialog.Builder(this)
        .setTitle("Memoria insuficiente")
        .setMessage("Tu dispositivo tiene poca memoria disponible. Cierra otras aplicaciones e intenta nuevamente.")
        .setPositiveButton("Reintentar") { _, _ ->
            // Sugerir liberar memoria
            System.gc()
            stampsSDK.startStamps(1)
        }
        .setNegativeButton("Cancelar") { dialog, _ ->
            dialog.dismiss()
        }
        .show()
}

private fun handleGenericError(error: String) {
    AlertDialog.Builder(this)
        .setTitle("Error")
        .setMessage("Ocurrio un error: $error\n\nDeseas intentar nuevamente?")
        .setPositiveButton("Reintentar") { _, _ ->
            stampsSDK.startStamps(1)
        }
        .setNegativeButton("Cancelar") { dialog, _ ->
            dialog.dismiss()
        }
        .show()
}

Ejemplos de Uso

Ejemplo 1: Implementacion Basica (Captura Inteligente)

@AndroidEntryPoint
class DocumentCaptureActivity : AppCompatActivity(), StampsListener {
    
    private lateinit var stampsSDK: StampsSDK
    private lateinit var binding: ActivityDocumentCaptureBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityDocumentCaptureBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // Inicializar SDK
        stampsSDK = StampsSDK(this, this)
        
        // Boton para iniciar captura
        binding.btnCapture.setOnClickListener {
            startDocumentCapture()
        }
    }
    
    private fun startDocumentCapture() {
        // Mostrar loading
        binding.progressBar.visibility = View.VISIBLE
        
        // Iniciar captura inteligente
        stampsSDK.startStamps(1)
    }
    
    override fun onSuccessStamps(
        typeProcess: Int,
        frontOriginalUri: Uri?,
        frontCropUri: Uri?,
        backOriginalUri: Uri?,
        backCropUri: Uri?,
        frontFaceCropUri: Uri?
    ) {
        binding.progressBar.visibility = View.GONE
        
        // Determinar tipo de documento
        val hasBack = backCropUri != null
        val documentType = if (hasBack) "INE/IFE" else "Pasaporte/Licencia"
        
        Toast.makeText(this, "Documento capturado: $documentType", Toast.LENGTH_SHORT).show()
        
        // Procesar imagenes
        processDocument(frontCropUri, backCropUri, frontFaceCropUri)
    }
    
    override fun onErrorStamps(error: String) {
        binding.progressBar.visibility = View.GONE
        
        Toast.makeText(this, "Error: $error", Toast.LENGTH_LONG).show()
        Log.e("Stamps", error)
    }
    
    private fun processDocument(
        frontUri: Uri?,
        backUri: Uri?,
        faceUri: Uri?
    ) {
        // Convertir a Base64
        val frontBase64 = frontUri?.let { Utils.uriToBase64(contentResolver, it) }
        val backBase64 = backUri?.let { Utils.uriToBase64(contentResolver, it) }
        val faceBase64 = faceUri?.let { Utils.uriToBase64(contentResolver, it) }
        
        // Enviar a tu API
        sendToServer(frontBase64, backBase64, faceBase64)
    }
    
    private fun sendToServer(front: String?, back: String?, face: String?) {
        // Implementa tu logica de API aqui
        lifecycleScope.launch {
            try {
                apiService.uploadDocument(front, back, face)
                showSuccess()
            } catch (e: Exception) {
                showError(e.message)
            }
        }
    }
}

Preguntas Frecuentes (FAQ)

El SDK funciona offline?

Si, el SDK funciona completamente offline. No requiere internet para capturar ni procesar documentos. Solo necesita validar la licencia una vez al inicio (que se cachea).

Que formatos de imagen produce?

El SDK genera imagenes en formato JPEG optimizadas para procesamiento. Los archivos originales son de 1-5 MB, los recortados de 200-800 KB, y los rostros de 10-50 KB.

Puedo usar mi propio OCR?

Si, el SDK solo captura las imagenes. Tu decides que hacer con ellas: OCR, validacion, almacenamiento, etc.

Funciona con todos los dispositivos?

El SDK funciona en dispositivos Android 6.0+ (API 23) con camara funcional. Esta optimizado para todos los rangos (gama baja, media, alta).

Los datos se envian a servidores de JAAK?

No, el SDK trabaja completamente local. Las imagenes se guardan en el almacenamiento de tu app. Tu decides que hacer con ellas.

Cuanto espacio requiere?

El SDK en si ocupa aproximadamente 5 MB. Las imagenes capturadas varian segun configuracion, tipicamente 2-10 MB por documento completo.

Soporta documentos internacionales?

Si, el SDK detecta y captura cualquier documento tipo tarjeta. Esta optimizado para documentos mexicanos pero funciona con cualquier pais.


Contacto y Soporte

Soporte Tecnico

  • Email: [email protected]
  • Horario: Lunes a Viernes, 9:00 - 18:00 (UTC-6)
  • Tiempo de respuesta: 24-48 horas

Solicitar Licencia

Para obtener una licencia del SDK:

  1. Enviar email a [email protected]
  2. Incluir: Nombre de empresa, package name de app, proposito de uso
  3. Licencias de desarrollo son gratuitas
  4. Licencias de produccion tienen costo segun volumen

Reportar Problemas

Si encuentras algun problema:

  1. Activa setShowDebugMode(true)
  2. Reproduce el error
  3. Copia los logs completos
  4. Envia email a soporte con:
    • Descripcion del problema
    • Logs de error
    • Version del SDK
    • Modelo y version de Android del dispositivo
    • Capturas de pantalla si es posible

Ultima actualizacion: Noviembre 13, 2025
Version del documento: 1.0
Version del SDK: 1.2.0 Autor: JAAK AI - Equipo de Documentacion