react-native-ocr-package
Version:
A React component for scanning National Identity cards using a device's camera. This package integrates OCR technology to extract the text data from scanned cards by making API calls.
149 lines (125 loc) • 4.77 kB
JavaScript
import CameraComponent from './src/components/CameraComponent';
import LivenessDetection from './src/components/LivenessDetection';
import { Platform, NativeModules, InteractionManager, BackHandler } from 'react-native';
/**
* Utility function to manage the workflow between liveness detection and document scanning
* @param {Object} options Configuration options
* @param {string} options.ocrApiUrl The API endpoint for OCR processing
* @param {Function} options.onError Callback for any errors during the process
* @param {boolean} options.skipLiveness Optional flag to skip liveness and go directly to document scanning
* @returns {Object} An object with control methods
*/
const VerificationWorkflow = {
// Track if we're currently in a transition
_isTransitioning: false,
/**
* Start the verification process with liveness detection first
*/
startVerification: (options) => {
const {
ocrApiUrl,
onError,
skipLiveness = false,
transitionDelay = 3000, // Further increased delay to ensure stability
} = options || {};
// Reset transition flag
VerificationWorkflow._isTransitioning = false;
if (!ocrApiUrl) {
if (onError) onError(new Error('OCR API URL is required'));
return;
}
// Store for later use in the document scan
let livenessResult = null;
// Add an event listener to handle back button during transition (Android only)
const backHandler = Platform.OS === 'android' ?
BackHandler.addEventListener('hardwareBackPress', () => {
// During transitions, prevent going back to avoid restart issues
if (VerificationWorkflow._isTransitioning) {
return true; // Prevent default behavior
}
return false;
}) : null;
const proceedToDocumentScan = () => {
// Prevent duplicate transitions
if (VerificationWorkflow._isTransitioning) return;
VerificationWorkflow._isTransitioning = true;
// Ensure any native UI animations have completed
InteractionManager.runAfterInteractions(() => {
// Add a delay to allow native resources to clean up
setTimeout(() => {
// Remove the back handler when we're ready to proceed
if (backHandler) {
backHandler.remove();
}
VerificationWorkflow._isTransitioning = false;
// Notify caller that it's ready for document scanning
// Run this on the next frame to ensure the UI is ready
requestAnimationFrame(() => {
if (options.onReadyForDocumentScan) {
options.onReadyForDocumentScan(livenessResult);
}
});
}, transitionDelay);
});
};
// Skip liveness check if requested or not on Android
if (skipLiveness || Platform.OS !== 'android') {
proceedToDocumentScan();
return;
}
try {
// Quick platform check
if (Platform.OS !== 'android') {
proceedToDocumentScan();
return;
}
// Start liveness detection with a wrapped promise to ensure proper handling
const startLiveness = async () => {
try {
const isAvailable = await LivenessDetection.isAvailable();
if (!isAvailable) {
proceedToDocumentScan();
return;
}
// Start liveness detection and capture result
const result = await LivenessDetection.startLivenessDetection();
if (!result) {
proceedToDocumentScan();
return;
}
// Store liveness result and proceed
livenessResult = result;
// Clean up before proceeding
InteractionManager.runAfterInteractions(() => {
proceedToDocumentScan();
});
} catch (err) {
if (onError) onError(err);
// Still proceed to document scanning despite errors
setTimeout(() => {
proceedToDocumentScan();
}, 1000);
}
};
// Start the liveness flow
startLiveness();
} catch (error) {
if (onError) onError(error);
// Proceed to document scanning despite error
setTimeout(() => {
proceedToDocumentScan();
}, 1000);
}
},
/**
* Combines liveness and OCR results into a single result object
*/
combineResults: (livenessResult, ocrResult) => {
// Simple combination with no unnecessary structuring
return {
liveness: livenessResult || null,
ocr: ocrResult || null
};
}
};
export { CameraComponent, LivenessDetection, VerificationWorkflow };