Document-Detector SDK

Document Detector SDK es una herramienta que permite a las aplicaciones móviles capturar y procesar documentos con la cámara o bien elegir desde el almacenamiento interno.


Objetivo


Document Detector SDK es una solución eficiente para integrar el escaneo de documentos en aplicaciones móviles. Permite tomar fotos de documentos de manera automática utilizando la cámara del dispositivo o seleccionar imágenes directamente desde el almacenamiento. Gracias a su tecnología avanzada de detección y pre procesamiento, el SDK asegura que los documentos sean capturados correctamente en diversas condiciones, optimizando la calidad de las imágenes para un posterior análisis.


Funcionalidades


  • Detección Automática de Documentos: Utiliza la cámara del dispositivo para detectar documentos automáticamente, eliminando la necesidad de intervención manual.
  • Selección desde Almacenamiento: Permite a los usuarios elegir una imagen existente desde su almacenamiento, ideal para documentos ya guardados.
  • Visualización de Vista Previa: Los usuarios pueden ver las imágenes capturadas o seleccionadas antes de confirmarlas.
  • Conversión a Base64: Una vez que el usuario confirma las imágenes, el SDK convierte los documentos a formato base64, facilitando su envío a integradores o sistemas backend para su procesamiento.\

Empezando


Antes de integrar el SDK en tu proyecto, asegúrate de cumplir con los siguientes requisitos:

  • Android Studio: Tener instalada la versión recomendada de Iguana de Android Studio.
  • Gradle: Usar la versión recomendada de Gradle 8.4.
  • Android Gradle Plugin: Tener la versión recomendada del plugin de Gradle 8.3.2.
  • Compilación del SDK: Configurar la compilación con SDK 35.
  • Compatibilidad de Source y Target: Utilizar las versiones recomendadas de source y target compatibility 18.
  • minSdkVersion: Establecer la versión mínima del SDK en 26.
  • targetSdkVersion: Configurar la versión del SDK objetivo en 33.
  • Groovy DS: La configuración del build gradle, debe de estar en Groovy DSL.

Configuración

  1. Crear una aplicacion

Al crear un proyecto debe de elegirse como No Activity y en la opción de build Configuration Language se debe de elegir: Groovy DSL (build,gradle)

  1. Remplaza el contenido de build.gradle del proyecto por:
buildscript {
    ext.kotlin_version = "1.9.22"
    ext.hilt_version = '2.46'
    repositories {
        google()
        mavenCentral()
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven {
            url 'https://jitpack.io'
        }
    }
    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"
        classpath 'com.google.gms:google-services:4.4.2'
    }
}
tasks.register('clean', Delete) {
    delete rootProject.buildDir
}
  1. Remplaza en el archivo settings.gradle el siguiente bloque de dependencyResolutionManagement:
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven { url 'https://maven.microblink.com' }
    }
}
  1. Remplaza la sección de plugins en el archivo build.gradle de app
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

Remplaza la sección de dependencias en el archivo build.gradle de app

dependencies {
    //Código previo
    //..
    //.
// Bibliotecas de Kotlin
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
// Android Jetpack
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.fragment:fragment-ktx:1.8.5")
implementation("androidx.activity:activity-ktx:1.9.3")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
implementation("androidx.constraintlayout:constraintlayout:2.2.0")
implementation 'com.google.android.material:material:1.12.0'

// Inyección de Dependencias
implementation("com.google.dagger:hilt-android:$hilt_version")
kapt("com.google.dagger:hilt-android-compiler:$hilt_version")
// jaakdocumentdetector
implementation("com.jaak.documentdetectorsdk:jaakdocumentdetector-sdk:2.0.3")
}

Agrega el siguiente bloque en Android en el archivo build.gradle de app

android {
    //Código previo
    //..
    //.
    buildFeatures{
        viewBinding = true
    }
}
  1. Crea una clase kotlin que extienda de Application y agrega la anotación de HiltAndroidApp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class TestApp : Application()
  1. Crea una clase kotlin con la anotación @AndroidEntryPoint, que extienda de AppCompatActivity() e impolementa el listener DocumentDetectorListener

Ejemplo de Activity
Nota: Este ejemplo utiliza viewBinding por lo que se debe de crear un layout donde el nombre es como se armara la clase binding.

Ejemplo: layout: activity_main.xml --> El nombre del binding se llamaría ActivityMainBinding
Ejemplo 2: layout: main_activity.xml --> El nombre del binding se llamaría MainActivityBinding

class MainActivity : AppCompatActivity(), DocumentDetectorListener {

    private lateinit var binding: MainActivityBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    override fun onSuccessDocumentDetector(typeProcess: Int, uri: Uri?, uri2: Uri?) {
    }

    override fun onErrorDocumentDetector(text: String) {
    }

Crea una xml para utilizar los viewBinding

Nota: Al crear el xml se debe de agregar la línea:
xmlns:tools="http://schemas.android.com/tools" y la línea: tools:context="nombre_clase_kotlin"

Ejemplo 1: tools:context="com.jaak.jaakdocumentdetectorsdk.MainActivity"
Ejemplo 2: tools:context="com.jaak.jaakdocumentdetectorsdk.ActivityMain"

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.test.MainActivity">

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Agrega los permisos al archivo AndroidManifest
<manifest...>
      //Código previo
    		//..
   		  //..
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
          tools:replace="android:maxSdkVersion"
          android:maxSdkVersion="28"/>   
</manifest>  

Agrega las siguientes líneas a application para agregar nuestra App previamente creada, además de unas excepciones

 <application
        //Código previo
    		//..
   		  //..
        android:name="com.example.test.TestApp"
        tools:replace="android:theme,android:name">

Agrega la actividad principal que se creó previamente

<application ..>
      //Código previo
    		//..
   		  //..
        <activity android:name="com.example.test.MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
  1. Implementa la librería de document detector sdk:
private lateinit var documentDetectorSDK: DocumentDetectorSDK

Agregue su configuración:

Nota: Para poder utilizar la detección de documentos es necesario contar con una licencia y este debe de ingresarse en la línea de código:
documentDetectorSDK.setLicence("")

Para que la licencia sea válida, es necesario que proporciones al equipo de Operaciones el nombre del paquete, para que al generar la licencia, este se ligue con el proyecto.
El nombre del paquete del proyecto puede ser consultado en el archivo build.gradle de app en el apartado de android: defaultCondig : applicationId

Nombre de paquete:

defaultConfig {
    applicationId "com.example.test" // ejemplo de nombre de paquete
    minSdk 26
    targetSdk 34
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

Configuración:

private fun configFaceDetectorSDK(){
        documentDetectorSDK = DocumentDetectorSDK(this, this)
        documentDetectorSDK.setEnableCamera(true)
        documentDetectorSDK.setEnableDisk(true)
        documentDetectorSDK.setEnableCameraPhoto(true)
        documentDetectorSDK.setEnableDiskPhoto(true)
        documentDetectorSDK.setImageFormat("image/*")
        documentDetectorSDK.setImageSize(3)
        documentDetectorSDK.setLicence("")
    }

Ejecutar el SDK:

Nota: Si se quiere tener el menú de obtener imagen por cámara o por almacenamiento, se manda 0.
Si se quiere solo obtener imagen por cámara se manda 1 y si solo por almacenamiento se manda 3

documentDetectorSDK.startDocumentDetector(0)
  1. Obtener las imágenes y convertirlos en base64

En los métodos override del listener DocumentDetectorListener, al ser correcto, este devuelve la ubicación de las imágenes y para no llenar la memoria al manejar base64
se tiene el siguiente ejemplo para obtener las imágenes sea frontal o frontal/trasero:

override fun onSuccessDocumentDetector(typeProcess: Int, uri: Uri?, uri2: Uri?) {
            var base64Proccess = ""
            var base64Proccess2 = ""
            when (typeProcess) {
                1 -> {
                    base64Proccess = Utils.uriToBase64(contentResolver, uri!!)!!
                    if(uri2 != null){
                        base64Proccess2 = Utils.uriToBase64(contentResolver, uri2)!!
                    }
                }
                3 -> {
                    base64Proccess = Utils.uriToBase64(contentResolver, uri!!)!!
                }
                else -> {
                    Toast.makeText(this,getString(R.string.error_base64_empty), Toast.LENGTH_SHORT).show()
                }
            }
        Log.e("base64 1",uri.toString())
        Log.e("base64 2",uri2.toString())
    }

El integrador decide cómo proceder con las imágenes en base64

Ejemplo de Código


Ejemplo completo de código.

build.gradle Project

buildscript {
    ext.kotlin_version = "1.9.22"
    ext.hilt_version = '2.46'
    repositories {
        google()
        mavenCentral()
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven {
            url 'https://jitpack.io'
        }
    }
    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"
        classpath 'com.google.gms:google-services:4.4.2'
    }
}
tasks.register('clean', Delete) {
    delete rootProject.buildDir
}

settings.gradle

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }
        maven { url 'https://maven.microblink.com' }
    }
}

rootProject.name = "Test"
include ':app'

build.gradle App

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

android {
    namespace 'com.example.test'
    compileSdk 35

    defaultConfig {
        applicationId "com.example.test"
        minSdk 26
        targetSdk 34
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '11'
    }
    buildFeatures{
        viewBinding = true
    }
}

dependencies {
    // Bibliotecas de Kotlin
    implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
    // Android Jetpack
    implementation("androidx.core:core-ktx:1.15.0")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("androidx.fragment:fragment-ktx:1.8.5")
    implementation("androidx.activity:activity-ktx:1.9.3")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
    implementation("androidx.constraintlayout:constraintlayout:2.2.0")
    implementation 'com.google.android.material:material:1.12.0'

    // Inyección de Dependencias
    implementation("com.google.dagger:hilt-android:$hilt_version")
    kapt("com.google.dagger:hilt-android-compiler:$hilt_version")

    implementation("com.jaak.jaakdocumentdetectorsdk:jaakdocumentdetector-sdk:2.0.3")

}

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Ruta para acceder a archivos en el directorio de archivos externos privados de la aplicación -->
    <external-path name="my_images" path="Pictures/" />
    <external-path name="my_files" path="Android/data/com.example.test/files/Test/" />
</paths>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:replace="android:maxSdkVersion"
        android:maxSdkVersion="28"/>
    <application
        android:name="com.example.test.TestApp"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test1"
        tools:targetApi="31"
        tools:replace="android:theme,android:name">
        <activity android:name="com.example.test.MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

TestApp.kt

package com.example.test

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class TestApp : Application()

res/layout/main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.test.MainActivity">


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt

package com.example.test

import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.jaak.jaakdocumentdetectorsdk.databinding.MainActivityBinding
import com.jaak.jaakdocumentdetectorsdk.sdk.DocumentDetectorSDK
import com.jaak.jaakdocumentdetectorsdk.ui.adapter.DocumentDetectorListener
import com.jaak.jaakdocumentdetectorsdk.utils.Utils
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), DocumentDetectorListener {

    private lateinit var binding: MainActivityBinding
    private lateinit var documentDetectorSDK: DocumentDetectorSDK

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initComponents()
    }

    private fun initComponents(){
        documentDetectorSDK = DocumentDetectorSDK(this, this)
        configFaceDetectorSDK()
        documentDetectorSDK.startDocumentDetector(0)
    }

    private fun configFaceDetectorSDK(){
        documentDetectorSDK = DocumentDetectorSDK(this, this)
        documentDetectorSDK.setEnableCamera(true)
        documentDetectorSDK.setEnableDisk(true)
        documentDetectorSDK.setEnableCameraPhoto(true)
        documentDetectorSDK.setEnableDiskPhoto(true)
        documentDetectorSDK.setImageFormat("image/*")
        documentDetectorSDK.setImageSize(3)
        documentDetectorSDK.setLicence("")
    }

    override fun onSuccessDocumentDetector(typeProcess: Int, uri: Uri?, uri2: Uri?) {
        var base64Proccess = ""
        var base64Proccess2 = ""
        when (typeProcess) {
            1 -> {
                base64Proccess = Utils.uriToBase64(contentResolver, uri!!)!!
                if(uri2 != null){
                    base64Proccess2 = Utils.uriToBase64(contentResolver, uri2)!!
                }
            }
            3 -> {
                base64Proccess = Utils.uriToBase64(contentResolver, uri!!)!!
            }

        }
        Log.e("base64 1",uri.toString())
        Log.e("base64 2",uri2.toString())
    }

    override fun onErrorDocumentDetector(text: String) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
    }
}

Actualización

Se actualizo los repositorios de jaak para la descarga de componentes, el cual es el siguiente:

 maven {
            url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
        }

Se debe de reemplazar este para que pueda descargar el SDK..


Se actualiza nombre de librería de Document Detector SDK, quedando de la siguiente manera:

dependencies {
implementation("com.jaak.documentdetectorsdk:jaakdocumentdetector-sdk:2.0.3")
        }