Video Camera Recorder SDK

El Video Camera Recorder SDK se encarga de capturar videos en tiempo real desde el dispositivo del usuario. Este SDK permite grabar videos de alta calidad mientras asegura la integridad del proceso, ofreciendo características como la detección de calidad de la imagen y la grabación en condiciones de poca luz.

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:

  • Tomar una foto con la cámara del dispositivo Android y devolver su URI.
  • Grabar un video con la cámara del dispositivo Android y devolver su URI.

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.videocamerarecordersdk:jaakvideocamerarecorder-sdk:2.0.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 PhotoVideoCaptureListener

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(), PhotoVideoCaptureListener   {

    private lateinit var binding: MainActivityBinding

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

 // Method to receive the image URI
override fun onPhotoCameraCapture(uri: Uri?) {
}

// Method to receive the video URI
override fun onVideoCameraCapture(uri: Uri?) {
}

// Method to handle errors in the URI processing
override onErrorCaptured(errorText: 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 video camera recorder sdk:

private lateinit var photoVideoCameraSDK: PhotoVideoCameraSDK

Agregue su configuración::

 private fun initSDKPhotoVideoCamera(){
   photoVideoCameraSDK = PhotoVideoCameraSDK(this,this)
   photoVideoCameraSDK.setIsFaces(true)
}

Ejecutar el SDK:

// Initiate photo capture
photoVideoCameraSDK.startCameraPhoto()
// Initiate video capture
photoVideoCameraSDK.startCameraVideo()

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.videocamerarecordersdk:jaakvideocamerarecorder-sdk:2.0.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(), PhotoVideoCaptureListener  {

    private lateinit var binding: MainActivityBinding
		private lateinit var photoVideoCameraSDK: PhotoVideoCameraSDK

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

 private fun initSDKPhotoVideoCamera(){
   photoVideoCameraSDK = PhotoVideoCameraSDK(this,this)
    photoVideoCameraSDK.setIsFaces(true)
}

 // Method to receive the image URI
override fun onPhotoCameraCapture(uri: Uri?) {
}

// Method to receive the video URI
override fun onVideoCameraCapture(uri: Uri?) {
}

// Method to handle errors in the URI processing
override onErrorCaptured(errorText: String) {
}

}