Skip to main content

React Native

Nuestro SDK de Workflows para React Native permite una experiencia rápida y fluida para tus usuarios, aprovechando las capacidades nativas de los dispositivos. Este SDK se instala como un paquete npm y te permite ejecutar workflows, obtener información detallada del proceso y recibir eventos en tiempo real durante su ejecución.


Requisitos

Para poder utilizar nuestro SDK de React Native, debes cumplir con los siguientes requisitos:

  • React Native 0.70+
  • Node.js 18+
  • Contar con un Workflow creado a través de nuestra API de Workflows.
  • Acceso al registro privado de npm (se te proporcionará un archivo .npmrc).

Instalación

Configuración del archivo .npmrc

En la raíz del proyecto React Native, agrega el archivo .npmrc para autorizar la instalación del paquete. Este archivo te será proporcionado por tu administrador de cuenta.

Instalación del paquete

Ejecuta el siguiente comando en la raíz del proyecto:

npm install @rem-tools/workflows-react-native@0.5.0

Nota: Verifica la versión actual en el registro de npm.

Configuración para Expo

Si utilizas Expo, puedes omitir la configuración nativa usando el comando:

npx expo prebuild --clean

En tu archivo app.json o app.config.js, agrega la configuración del plugin:

{
"expo": {
"plugins": [
[
"@rem-tools/workflows-react-native",
{
"jsonKeyPath": "/ruta/a/tu/archivo-service-account.json",
"cameraDescription": "Se requiere acceso a la cámara para verificación de identidad",
"microphoneDescription": "Se requiere acceso al micrófono para grabar audio",
"locationDescription": "Se requiere acceso a la ubicación por motivos de seguridad"
}
]
]
}
}

Opciones de Configuración del Plugin

ParámetroRequeridoDescripción
jsonKeyPathRuta absoluta o relativa al archivo JSON de la cuenta de servicio de Google Cloud. Requerido para Android para autenticarse con el repositorio Maven privado.
cameraDescriptionNoDescripción personalizada para el permiso de cámara (iOS).
microphoneDescriptionNoDescripción personalizada para el permiso de micrófono (iOS).
locationDescriptionNoDescripción personalizada para el permiso de ubicación (iOS).

Ejecutar la aplicación

Para Android (dispositivo físico):

Asegúrate de que el proyecto Android haya completado el build de Gradle:

npm run android --device

Para iOS (dispositivo físico):

Asegúrate de haber ejecutado pod install en el directorio ios:

npx expo run:ios --device

Configuración Específica para Android

Requisitos de SDK de Android

  • Android API 29 - 36
  • Android Studio Hedgehog+

Configuración de Repositorios

En el archivo android/build.gradle, declara de dónde se obtendrán las dependencias:

allprojects {
repositories {
maven {
url "https://us-central1-maven.pkg.dev/gendra-services/workflows-mobile"
credentials {
username = "_json_key"
password = file("tu_archivo_credenciales.json").text
}
}
}
}
danger

El archivo de service account (JSON) es proporcionado por REM. Contacta a tu administrador de cuenta para obtenerlo.

Configuración de Release Build

En el archivo android/app/build.gradle, agrega a nivel de android los siguientes ajustes que permiten que Workflows pueda acceder a modelos, assets, y evitar errores en compilación de release:

android {
// ...

buildTypes {
release {
shrinkResources false
}
}

aaptOptions {
noCompress "tflite", "task"
}

sourceSets {
main {
assets.srcDirs += 'src/main/assets'
}
}
}
danger

No excluyas librerías .so requeridas por el SDK usando packagingOptions o packaging.jniLibs.

Por ejemplo, NO debes usar:

packagingOptions {
exclude 'lib/arm64-v8a/libPhoenixAndroid.so'
}

El SDK depende de librerías nativas como:

lib/arm64-v8a/libPhoenixAndroid.so

Si se excluyen, la aplicación puede compilar pero fallará en ejecución, especialmente en la inicialización de biometría.

Configuración del AndroidManifest

Agrega esta línea para resolver conflictos del AndroidManifest cuando una librería (como Workflows) define los mismos atributos:

<application
...
tools:replace="android:theme, android:usesCleartextTraffic">
...
</application>

Reglas para ProGuard

Agrega las siguientes reglas al archivo proguard-rules.pro. Son necesarias para evitar la minificación de clases usadas por Workflows:

#Rules for the Workflows Flutter
-keep class tools.rem.workflows_flutter_plugin.** { *; }
-keep class tools.rem.workflows_flutter_plugin.Models.Step.Step { *; }
-keep class tools.rem.workflows_flutter_plugin.Models.Workflow.Workflow { *; }
-keep class tools.rem.workflows_flutter_plugin.Models.WorkflowError { *; }
-keep class tools.rem.workflows_flutter_plugin.WorkflowsFlutterPlugin { *; }
-keepclassmembers class tools.rem.workflows_flutter_plugin.Models.Workflow.Workflow {
public <init>(...);
}
-keep class tools.rem.workflows_flutter_plugin.Models.ConfigFacetec { *; }
-keepclassmembers class tools.rem.workflows_flutter_plugin.Models.ConfigFacetec {
public <init>(...);
}

#Keep the mediapipe classes
-keep public class com.google.mediapipe.framework.Graph.** { *; }
-keep interface com.google.common.** { *; }
-keep class * extends com.google.common.flogger.** {*;}
-keep class com.google.common.** { *; }
-keep class com.google.common.flogger.** { *; }
-keep class com.google.mediapipe.tasks.** { *; }
-keep class com.google.mediapipe.tasks.vision.** { *; }
-keep class com.google.mediapipe.tasks.core.** { *; }
-keep class com.google.mediapipe.framework.ProtoUtil$* { *; }
-keep class com.google.mediapipe.framework.** { *; }
-keep class com.google.mediapipe.framework.image.** { *; }
-keep class com.google.mediapipe.** { *; }
-keep class com.google.mediapipe.proto.** { *; }
-keep class javax.lang.model.** { *; }
-keep class com.google.mediapipe.solutioncore.** { *; }
-keep class com.google.protobuf.** { *; }
-keep class org.tensorflow.lite.** { *; }
-dontwarn com.google.mediapipe.proto.CalculatorProfileProto$CalculatorProfile
-dontwarn com.google.mediapipe.proto.GraphTemplateProto$CalculatorGraphTemplate
-dontwarn org.tensorflow.lite.**
-dontwarn javax.annotation.**
-dontwarn javax.lang.model.**
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite.** { *; }
-keepclassmembers class com.google.mediapipe.**$$ExternalSyntheticLambda* { *; }
-keepattributes InnerClasses,EnclosingMethod,Signature,*Annotation*

#Keep the okhttp3 classes
-keep class okhttp3.** { *; }
-keep class okio.** { *; }

#Keep the gson classes
-keep class com.google.gson.** { *; }

#Keep the facetec classes
-dontwarn javax.annotation.Nullable
-dontwarn com.facetec.sdk.**
-keep,includecode,includedescriptorclasses class com.facetec.sdk.** { *; }

#Keep the cameraview classes
-keep class com.otaliastudios.cameraview.** { *; }
-dontwarn com.otaliastudios.cameraview.**

Recursos Personalizados

Para usar recursos personalizados, agrega los assets en la carpeta res según su tipo:

CarpetaTipo de RecursoFormatos
drawableImágenes.png, .jpeg
fontTipografías.ttf, .otf
rawImágenes vectoriales.svg
xmlTextos localizados.xml

Configuración Específica para iOS

Requisitos de iOS

  • iOS 15.1 - 26.0
  • Xcode 14.0+

Configuración del Podfile

En el archivo ios/Podfile, establece la versión mínima en 15.1 y agrega el pod de WorkflowController:

platform :ios, '15.1'

target 'TuApp' do
# Otras configuraciones y pods
pod 'WorkflowControllerDebug',
:podspec => 'https://storage.googleapis.com/workflows-mobile-sdk-artifacts/WorkflowiOS/WorkflowController/WorkflowsControllerDebug.podspec?cache=1225',
:configurations => ['Debug']
pod 'WorkflowControllerRelease',
:podspec => 'https://storage.googleapis.com/workflows-mobile-sdk-artifacts/WorkflowiOS/WorkflowController/WorkflowsControllerRelease.podspec?cache=1225',
:configurations => ['Release']
end

Nota: El target WorkflowsReactNative es generado automáticamente por CocoaPods al instalar este paquete. No es necesario modificar este nombre.

Agrega el siguiente bloque post_install en tu Podfile:

post_install do |installer|

media_pipe_source = if File.exist?("Pods/WorkflowControllerDebug")
"WorkflowControllerDebug"
elsif File.exist?("Pods/WorkflowControllerRelease")
"WorkflowControllerRelease"
else
nil
end
system("mv Pods/#{media_pipe_source}/MediaPipeTasks*.xcframework Pods/") if media_pipe_source
installer.pods_project.targets.each do |target|
if target.name == 'WorkflowsReactNative'
puts "[WorkflowSDK] MATCHED Pod Target: WorkflowsReactNative"
group = target.project.main_group.find_subpath("Pods/#{media_pipe_source}", true) if media_pipe_source
%w(MediaPipeTasksVision.xcframework MediaPipeTasksCommon.xcframework).each do |fw|
file_path = File.join(Pod::Config.instance.installation_root, "Pods", media_pipe_source, fw)
puts "[WorkflowSDK] Adding #{fw} to #{target.name}"
ref = group.new_file(file_path)
ref.source_tree = 'SOURCE_ROOT'
target.frameworks_build_phase.add_file_reference(ref, true)
build_files = target.frameworks_build_phase.files.select { |f| f.file_ref == ref }
build_files.each { |bf| bf.settings = { 'ATTRIBUTES' => ['Required'] } }
end
end
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.1'
config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = "arm64"
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
installer.pods_project.save
end

Instalación de Dependencias

Desde la carpeta ios de tu proyecto, ejecuta:

pod install

Importante: Recomendamos limpiar las dependencias de CocoaPods antes de volver a instalar.

Desde la carpeta ios, ejecuta:

rm -rf Pods
rm Podfile.lock
pod install

Esto asegura que las dependencias nativas se reinstalen correctamente y evita conflictos con versiones previamente instaladas.


Permisos en Info.plist

Agrega los permisos necesarios al archivo Info.plist o en el target properties seleccionando la pestaña Info:

<key>NSCameraUsageDescription</key>
<string>3D Liveness Detection by FaceTec.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to record audio.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>The example App requires access to the devices location.</string>

Recursos Personalizados

Para usar recursos personalizados, agrégalos directamente a la carpeta del proyecto:

Tipo de RecursoFormatoUbicación
Textos.stringsCarpeta del proyecto
Imágenes SVG.svgCarpeta del proyecto
Tipografías.otf, .ttfCarpeta del proyecto
Imágenes PNG/JPG.png, .jpgAsset Catalog

Uso del SDK

Importación

Importa los componentes necesarios del SDK:

import type { WorkflowCustomization } from '@rem-tools/workflows-react-native';
import {
closeWorkflow,
useWorkflow,
useWorkflowEvents,
verifyWorkflowsLicense
} from '@rem-tools/workflows-react-native';

Verificación de Licencia

Antes de iniciar un workflow, debes verificar la licencia del SDK:

verifyWorkflowsLicense({
cert: "tu_certificado", // Base64-encoded PFX
passphrase: "tu_passphrase" // Base64-PFX passphrase
});
danger

Las credenciales de licencia (cert y passphrase) serán compartidas de forma privada por tu administrador de cuenta.

Inicialización del Workflow

Utiliza el hook useWorkflow para configurar y lanzar un workflow:

const launchWorkflow = useWorkflow({
baseUrl: 'https://api.rem.tools', // Your Workflows backend URL
apiKey: 'tu_api_key', // Your API key
workflowId: 'tu_workflow_id', // Workflow ID to execute
customization: getWorkflowCustomization() // null = default UI, or customize
});

Manejo de Eventos

Utiliza el hook useWorkflowEvents para escuchar los eventos del workflow:

const { workflowStart, workflowEvent, workflowStep } = useWorkflowEvents();

// Evento de inicio del workflow
useEffect(() => {
if (workflowStart) {
console.log("Workflow started success:", workflowStart.success);
if (workflowStart.error !== undefined) {
console.log("Workflow Id Error:", workflowStart.error);
}
}
}, [workflowStart]);

// Eventos del workflow
useEffect(() => {
if (workflowEvent) {
console.log("Workflow UUID:", workflowEvent.uuid, "Status:", workflowEvent.status);
if (workflowEvent.error) {
console.log("Workflow Error:", workflowEvent.error);
}
}
}, [workflowEvent]);

// Eventos de pasos
useEffect(() => {
if (workflowStep) {
console.log("Step:", workflowStep.step, "Status:", workflowStep.status);
const error = workflowStep.error;
if (error && (workflowStep.status === "error" || workflowStep.status === "failed")) {
console.log("Error - fatal:", error.fatal,
"errorId:", error.details?.errorId,
"reason:", error.details?.reason);

const extra = error.extra;
if (extra) {
if (extra.idScanStatus != null || extra.faceScanStatus != null) {
console.log("idScanStatus:", extra.idScanStatus,
"faceScanStatus:", extra.faceScanStatus);
}
if (extra.permission != null) {
console.log("Permission denied:", extra.permission);
// Cerrar la actividad/vista de workflows
closeWorkflow();
}
if (extra.secure != null) {
console.log("Is device secure:", extra.secure);
}
if (extra.isLicenseValid != null) {
console.log("Is license valid:", extra.isLicenseValid);
}
}
}
}
}, [workflowStep]);

Lanzar el Workflow

Para lanzar la pantalla de workflows, simplemente llama al hook:

<Button title="Iniciar Workflow" onPress={launchWorkflow} />

Cerrar el Workflow

Workflows se abre en una nueva activity/controller. Para cerrar, usa la función closeWorkflow():

closeWorkflow();

Personalización del SDK

Puedes personalizar la apariencia del SDK mediante la función de configuración:

import { Platform } from 'react-native';

function getWorkflowCustomization(): WorkflowCustomization {
return {
theme: {
primaryColor: '#61DBFB',
secondaryColor: '#20232A',
buttonPrimaryColor: '#61DBFB',
buttonSecondaryColor: '#20232A',
buttonTextPrimaryColor: '#FF6F61',
buttonTextSecondaryColor: '#F9A826',
backgroundColor: '#F5F5F5',
facetecOverlayColor: '#F5F5F5',
showHeaderLogo: true
},
textLocalization: {
localization: Platform.OS === 'android'
? 'localizable.xml'
: 'Localizable.strings'
},
textFont: {
headerFont: Platform.OS === 'android'
? 'montserrat_black.ttf'
: 'Montserrat-Black.ttf',
bodyFont: Platform.OS === 'android'
? 'montserrat_regular.ttf'
: 'Montserrat-Regular.ttf',
buttonFont: Platform.OS === 'android'
? 'playwrite_ar_regular.ttf'
: 'PlaywriteAR-Regular.ttf'
},
images: {
logo: 'logo.png',
cameraPermissions: 'cam.png',
uploadFaceScan: 'upload.png',
uploadFaceSuccess: 'exito_success.png',
uploadFaceError: 'error_image.png',
photoMathId: 'id.png',
photoMathIdBack: 'id_back.png',
cameraActiveTorch: 'on_flash.png',
cameraInactiveTorch: 'off_flash.png',
fingerPrint: 'fing.png',
successPage: 'success.svg',
errorPage: 'error.svg',
unavailablePage: 'error.svg',
locationPage: 'ubicacion.svg',
biometricSignPage: 'face_match.svg',
enrollFingerprintPage: 'face_match.svg',
enrollBasicPage: 'face_match.svg',
enrollFullPage: 'face_match.svg',
authPage: 'face_match.svg',
livenessPage: 'face_match.svg',
faceEnrollment3dPage: 'face_match.svg'
}
};
}

Ejemplo Completo

import React, { useEffect } from 'react';
import { View, Button, Platform } from 'react-native';
import type { WorkflowCustomization } from '@rem-tools/workflows-react-native';
import {
closeWorkflow,
useWorkflow,
useWorkflowEvents,
verifyWorkflowsLicense
} from '@rem-tools/workflows-react-native';

function getWorkflowCustomization(): WorkflowCustomization {
return {
theme: {
primaryColor: '#61DBFB',
secondaryColor: '#20232A',
buttonPrimaryColor: '#61DBFB',
buttonSecondaryColor: '#20232A',
buttonTextPrimaryColor: '#FFFFFF',
buttonTextSecondaryColor: '#FFFFFF',
backgroundColor: '#F5F5F5',
facetecOverlayColor: '#000000',
showHeaderLogo: true
},
textLocalization: {
localization: Platform.OS === 'android'
? 'localizable.xml'
: 'Localizable.strings'
},
textFont: {
headerFont: Platform.OS === 'android'
? 'montserrat_black.ttf'
: 'Montserrat-Black.ttf',
bodyFont: Platform.OS === 'android'
? 'montserrat_regular.ttf'
: 'Montserrat-Regular.ttf',
buttonFont: Platform.OS === 'android'
? 'montserrat_bold.ttf'
: 'Montserrat-Bold.ttf'
},
images: {
logo: 'logo.png',
cameraPermissions: 'camera.png',
uploadFaceScan: 'upload.png',
uploadFaceSuccess: 'success.png',
uploadFaceError: 'error.png',
photoMathId: 'id.png',
photoMathIdBack: 'id_back.png',
cameraActiveTorch: 'flash_on.png',
cameraInactiveTorch: 'flash_off.png',
fingerPrint: 'fingerprint.png',
successPage: 'success.svg',
errorPage: 'error.svg',
unavailablePage: 'unavailable.svg',
locationPage: 'location.svg',
biometricSignPage: 'biometric.svg',
enrollFingerprintPage: 'fingerprint.svg',
enrollBasicPage: 'enroll.svg',
enrollFullPage: 'enroll_full.svg',
authPage: 'auth.svg',
livenessPage: 'liveness.svg',
faceEnrollment3dPage: 'face_3d.svg'
}
};
}

export default function WorkflowScreen() {
// Verificar licencia al iniciar
useEffect(() => {
verifyWorkflowsLicense({
cert: "tu_certificado",
passphrase: "tu_passphrase"
});
}, []);

// Configurar el workflow
const launchWorkflow = useWorkflow({
baseUrl: 'https://api.rem.tools',
apiKey: 'tu_api_key',
workflowId: 'tu_workflow_id',
customization: getWorkflowCustomization()
});

// Escuchar eventos
const { workflowStart, workflowEvent, workflowStep } = useWorkflowEvents();

useEffect(() => {
if (workflowStart) {
console.log("Workflow started:", workflowStart.success);
}
}, [workflowStart]);

useEffect(() => {
if (workflowEvent) {
console.log("Workflow status:", workflowEvent.status);
}
}, [workflowEvent]);

useEffect(() => {
if (workflowStep) {
console.log("Step status:", workflowStep.status);
}
}, [workflowStep]);

return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="Iniciar Workflow" onPress={launchWorkflow} />
</View>
);
}

FAQ

¿Cómo obtengo el workflowId?

El workflowId se obtiene al crear un Workflow mediante nuestra API de Workflows. La respuesta de la API te proporcionará este identificador.

¿Cómo consigo el apiKey y el baseUrl?

El apiKey es proporcionado de forma privada, y el baseUrl suele ser:

  • https://api.rem.tools para producción.
  • https://api.test.rem.tools para pruebas.

¿Cómo obtengo las credenciales de licencia?

Las credenciales de licencia (cert y passphrase) para la función verifyWorkflowsLicense serán compartidas de forma privada por tu administrador de cuenta.

¿Cómo cierro el workflow programáticamente?

Utiliza la función closeWorkflow() que se importa del SDK. Esto cerrará la activity/controller del workflow.

tip

Si tienes alguna duda o problema con la integración del SDK, por favor contacta a soporte.

rem

JOIN US ON

facebooktwitterLinkedIn
CONTACThello@rem.tools55-91-03-80-54
© Copyright rem 2022 All rights reserved.