File Uploader SDK

El File Uploader SDK facilita la carga de documentos e imágenes al sistema durante el proceso de KYC. Este componente maneja la transferencia de archivos desde la aplicación móvil o la interfaz web hacia el servidor de backend de manera rápida, segura y eficiente. Asegura que los archivos sean validados, codificados y almacenados correctamente para su posterior procesamiento. Este SDK también puede manejar diferentes formatos de archivo, como imágenes y videos, asegurando la versatilidad en la carga de documentos.


Objetivo

El objetivo es facilitar la integración de capacidades avanzadas de carga de archivos en aplicaciones Android, permitiendo la selección de imágenes y videos con opciones de personalización flexible y recuperación de URI para un uso sencillo en la aplicación.

Funcionalidades

El SDK proporciona funcionalidades para:

  • Obtener una imagen del dispositivo Android y devolver su URI.
  • Obtener un video del dispositivo Android y devolver su URI.
  • Personalizar el tamaño máximo permitido para la carga de imágenes o videos.
  • Personalizar los formatos deseados de imagen o video.

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.

Configuracion

1. Crear una aplicación

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)

2. 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
}

3. 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'
        }
		}
}

4. 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.fileuploadersdk:jaakfileuploader-sdk:1.1.1")
}

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

android {
    //Código previo
    //..
    //.
    buildFeatures{
        viewBinding = true
    }
}

5. 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()

6. Crea una clase kotlin con la anotación @AndroidEntryPoint, que extienda de AppCompatActivity() e implementa el listener FaceDetectorListener

Ejemplo de ActivityNota: 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 ActivityMainBindingEjemplo 2: layout: main_activity.xml --> El nombre del binding se llamaría MainActivityBinding

class MainActivity : AppCompatActivity(), ImageVideoSelectionListener  {

    private lateinit var binding: MainActivityBinding

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

   // Method to return the image URI
	override fun onImageSelected(uri: Uri) {
	}

	// Method to return the video URI    
	override fun onVideoSelected(uri: Uri) {
	}

	// Method to return an error in the URI process
	override fun onErrorSelected(error: 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.example.test.MainActivity"
Ejemplo 2: tools:context="com.example.test.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>

7. 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>

Crearemos un archivo en res/xml/file_paths.xml que contendrá la ruta donde queremos que almacene los videos:

<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/nombre-de-tu-paquete/files/nombre-de-tu-root-name/" />
</paths>

Aqui está un ejemplo de su llenado:

<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>

Agregaremos el file provider al Manifest:

Nota: en android:authorities debe de ir el nombre del paquete del proyecto:Ejemplo 1: android:authorities="com.example.jaakfacedetectorsdk" Ejemplo 2: android:authorities="com.example.test"

<application ..>
  //Código previo
    //..
    //..
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.test"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>  
</application>

8. Implementa la librería de face detector sdk:

private lateinit var fileUploaderSDK: FileUploaderSDK

Agregue su configuración::

private fun initSDKImageVideoDisk(){
fileUploaderSDK = FileUploaderSDK(this, this)
fileUploaderSDK.setImageSize(3) // Maximum size for images: 3 MB
fileUploaderSDK.setVideoSize(10) // Maximum size for videos: 10 MB
fileUploaderSDK.setFormatImage(arrayOf("image/*")) // Allowed formats for images
fileUploaderSDK.setFormatVideo(arrayOf("video/*")) // Allowed formats for videos
}

Ejecutar el SDK:

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

fileUploaderSDK.startImageVideo(typeProcess)

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'
        }
    }
}

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 35
        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")
    // jaakdocumentdetector
		implementation("com.jaak.fileuploadersdk:jaakfileuploader-sdk:1.1.1")
}

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Ruta para acceder a archivos en el directorio externo privado de archivos 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: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.Test"
        tools:targetApi="31"
        android:name="com.example.test.TestApp"
        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>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.test"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </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 androidx.appcompat.app.AppCompatActivity
import com.example.test.databinding.MainActivityBinding
import com.jaak.jaakfacedetectorsdk.ui.adapter.FaceDetectorListener
import com.jaak.jaakfacedetectorsdk.ui.view.FaceDetectorSDK
import com.jaak.jaakfacedetectorsdk.utils.Utils
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), ImageVideoSelectionListener {

    private lateinit var binding: MainActivityBinding
    private lateinit var fileUploaderSDK: FileUploaderSDK

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

  private fun initSDKImageVideoDisk(){
    fileUploaderSDK = FileUploaderSDK(this, this)
    fileUploaderSDK.setImageSize(3) // Maximum size for images: 3 MB
    fileUploaderSDK.setVideoSize(10) // Maximum size for videos: 10 MB
    fileUploaderSDK.setFormatImage(arrayOf("image/*")) // Allowed formats for images
    fileUploaderSDK.setFormatVideo(arrayOf("video/*")) // Allowed formats for videos
	}

      // Method to return the image URI
	override fun onImageSelected(uri: Uri) {
	}

	// Method to return the video URI    
	override fun onVideoSelected(uri: Uri) {
	}

	// Method to return an error in the URI process
	override fun onErrorSelected(error: String) {
	}
}