Integration Documentation for React Native Compatible with Liveness Detection V4.x Version.
Minimum Android version:4.4 (API Level:19)
Compilation Android SDK version:API Level:35
Target Android SDK version:API Level:35
Supported CPU architectures:armeabi-v7a,arm64-v8a
SDK incremental package size:4.5MB+
If you have requirements for package size, you can refer to this to reduce the package size by approximately 1.4MB.
Capture image size:default capture image resolution 600px*600px, size is about 300KB, support custom image size range: 300px~1000px
Supported languages:
Use-permissions:
<uses-feature android:name="android.hardware.camera" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.CAMERA" />SDK requirements and limitations as below:
Nonearm64, x86_646.9MB(arm64, disable bitcode)NOen, zh-Hans, id, vi, th, es, ms, hi,filNSCameraUsageDescriptionClick to view the compliance explanation
Install IDV-Demo.apk to your phone and log in with the test account.
If you are upgrading from an older version of the Liveness SDK, please refer to this document to understand the changes.
Add the dependency in your React Native project’s package.json file.
"dependencies" ... "liveness-plugin""^4.1.2" ,For Android, you need to do:
Add the Maven repository to the settings.gradle or build.gradle file in the Android directory of your React Native project:
rootProject.allprojects { repositories { google() jcenter() repositories { maven { url 'https://public-n3.advai.net/repository/maven-releases/' } } }}For iOS, you need to do:
Podfile.xpod 'AAILivenessUI', :http => 'https://prod-guardian-cv.oss-ap-southeast-5.aliyuncs.com/sdk/iOS-liveness-detection/4.1.1/iOS-Liveness-SDK-V4.1.1.tar.bz2', type: :tbz
pod 'AAILivenessModel', :http => 'https://prod-guardian-cv.oss-ap-southeast-5.aliyuncs.com/sdk/iOS-libraries/AAILivenessModel/4.0.0/AAILivenessModel-V4.0.0.tar.bz2', type: :tbz
pod 'AAICore', :http => 'https://prod-guardian-cv.oss-ap-southeast-5.aliyuncs.com/sdk/iOS-libraries/AAICore/1.0.1/AAICore-V1.0.1.tar.bz2', type: :tbz
pod 'AAINetwork', :http => 'https://prod-guardian-cv.oss-ap-southeast-5.aliyuncs.com/sdk/iOS-libraries/AAINetwork/AAINetwork-V1.0.4.tar.bz2', type: :tbz
pod 'AAIDataVisorSDK', :http => 'https://prod-guardian-cv.oss-ap-southeast-5.aliyuncs.com/sdk/iOS-AAIDataVisor-SDK/0.1.5/iOS-AAIDataVisorSDK-V0.1.5.tar.bz2', type: :tbzpod install to install the dependencies in your project.<key>NSCameraUsageDescription</key><string>Use the camera to detect the face movements</string>Initialization SDK.
const SELECTED_MARKET: Market = 'Indonesia';await initSDKOfLicense(SELECTED_MARKET);Check license
The license is obtained by your server calling our openAPI, you need to check license before starting the liveness detection activity.
const license = "xxx";const result = await setLicenseAndCheck(license);if (result === 'SUCCESS') { startLivenessDetection()}The returned values of checkResult:
APPLICATION_ID_NOT_MATCH: The package name is not within the authorized scope, please check your package name.
LICENSE_EXPIRE: The license has expired, please confirm that the user has calibrated the phone time.
ERROR_LICENSE(1): The license parsing succeeded, but necessary authentication information is missing, this case generally will not occur.
ERROR_LICENSE(2): The license parsing succeeded, but the internal format is incorrect, this case also generally will not occur.
ERROR_LICENSE(3): It is highly likely that an incompatible SDK license is being used, such as using an IQA license for liveness detection.
ERROR_LICENSE(4, 5): Parsing failed, please check if the license has issues like mismatched quotes, line breaks, etc.
3. You can create SDK launch parameters using the method below```javascriptimport { useState, useEffect } from 'react';import {StyleSheet,View,Text,Button,ScrollView,SafeAreaView,ActivityIndicator,StatusBar,Image,Alert,Platform,} from 'react-native';// Import all methods and types from your pluginimport {getSDKVersion,initSDKOfLicense,setLicenseAndCheck,startLivenessDetection,} from 'liveness-plugin';import type { Market } from 'liveness-plugin';import type { LivenessDetectionResult } from 'liveness-plugin';import type { LivenessParams } from 'liveness-plugin';// --- Configuration Constants ---// Please replace with your real License keyconst YOUR_LICENSE_KEY = '';// Select a marketconst SELECTED_MARKET: Market = 'Indonesia';export default function App() {// --- State Management ---const [sdkVersion, setSdkVersion] = useState<string>('');const [livenessResult, setLivenessResult] =useState<LivenessDetectionResult | null>(null);const [isLoading, setIsLoading] = useState<boolean>(false);const [statusMessage, setStatusMessage] = useState<string>('Ready.');// --- Effect Hook: Get SDK version when the component mounts ---useEffect(() => {// Define an async function to fetch the versionconst fetchVersion = async () => {try {const version = await getSDKVersion();setSdkVersion(version);} catch (error) {console.error('Failed to get SDK version:', error);setSdkVersion('Error fetching version');}};fetchVersion();}, []); // Empty dependency array, runs only once when the component first mounts// --- Core Business Logic: The flow executed when the button is pressed ---const handleStartLiveness = async () => {setIsLoading(true); // Start loadingsetLivenessResult(null); // Clear old resultstry {// Step 1: Initialize SDK (with License)setStatusMessage(`Initializing SDK for ${SELECTED_MARKET}...`);await initSDKOfLicense(SELECTED_MARKET);console.log('SDK initialized with license.');// Step 2: Set and check the LicensesetStatusMessage('Setting and checking license...');const checkResult = await setLicenseAndCheck(YOUR_LICENSE_KEY);console.log('License check result:', checkResult);// Step 3: Check the license result, start liveness detection if successfulif (checkResult === 'SUCCESS') {setStatusMessage('License check passed. Starting liveness detection...');// Step 4: Define liveness detection parameters// Note: All parameters are optional.const livenessParams: LivenessParams = {cameraType: 'FRONT',queryId: 'your_query_id', // Replace with your query IDticket: 'your_ticket', // Replace with your ticketdetectOcclusion: false, // Whether to detect occlusionauditImageConfig: {enableCollectSwitch: true, // Whether to enable the collection switchimageWidth: 400, // Image widthimageQuality: 30, // Image qualityrelativeSecondsCaptureAfterCameraLaunched: 3.0, // Capture at a relative number of seconds after the camera is launched},livenessType: 'test_more', // Liveness detection typesignatureId: '', // Signature ID, if availabledistantNearTimeout: 50000, // Timeout for distant-near detection in millisecondssilentTimeout: 50000, // Timeout for silent detection in millisecondsactionTimeout: 10000, // Timeout for actions in millisecondsprepareMillSeconds: 0, // Preparation time in millisecondsresultPictureSize: 600, // Result picture sizemaxRecordVideoSeconds: 60, // Maximum video recording time in secondsuserId: '', // User ID, in JSON string formatmaskColor: '#000000', // Mask colorovalColor: '#000000', // Oval colorovalNormalColor: '#000000', // Normal oval color};// Step 5: Call liveness detection and pass a callback function to handle the resultstartLivenessDetection(livenessParams, (result) => {console.log('Liveness detection result received:', result);setStatusMessage('Liveness detection finished.');setLivenessResult(result); // Save the result to state for displaysetIsLoading(false); // Stop loading});// Note: startLivenessDetection itself is launched asynchronously.// The result will be returned via callback at a future point, so there's nothing more to do here.} else {// License check failedthrow new Error(`License check failed with result: ${checkResult}`);}} catch (error: any) {// Catch any error in the entire processconsole.error('Liveness process failed:', error);setStatusMessage(`Error: ${error.message}`);Alert.alert('Error',error.message || 'An unknown error occurred during the process.');setIsLoading(false); // Stop loading}};// --- Render UI ---return (<SafeAreaView style={styles.safeArea}><StatusBar barStyle={'dark-content'} /><View style={styles.container}><View style={styles.header}><Text style={styles.title}>Liveness Plugin Example</Text><Text style={styles.versionText}>SDK Version: {sdkVersion}</Text></View><View style={styles.buttonContainer}><Buttontitle="Start Liveness"onPress={handleStartLiveness}disabled={isLoading} // Disable button while loading/></View><View style={styles.statusContainer}>{isLoading && <ActivityIndicator style={styles.loader} />}<Text style={styles.statusText}>{statusMessage}</Text></View><View style={styles.resultContainer}><Text style={styles.resultTitle}>Detection Result:</Text><ScrollView style={styles.resultScrollView}><Text style={styles.resultJson}>{livenessResult? `isSuccess: ${livenessResult.isSuccess}\n` +`livenessId: ${livenessResult.livenessId ?? 'N/A'}\n` +`eventId: ${livenessResult.eventId ?? 'N/A'}\n` +`code: ${livenessResult.code ?? 'N/A'}\n` +`videoFilePath: ${livenessResult.videoFilePath ?? 'N/A'}\n` +`message: ${livenessResult.message ?? 'N/A'}\n` +`transactionId: ${livenessResult.transactionId ?? 'N/A'}\n` +`isPay: ${livenessResult.isPay ?? 'N/A'}`: 'No result yet.'}</Text>{livenessResult && livenessResult.base64Image && (<View style={styles.imageContainer}><Text style={styles.imageLabel}>Liveness Image:</Text><Imagestyle={styles.livenessImage}source={{uri: `data:image/jpeg;base64,${livenessResult.base64Image}`,}}/></View>)}</ScrollView></View></View></SafeAreaView>);}const styles = StyleSheet.create({safeArea: {flex: 1,backgroundColor: '#F5F5F5',},container: {flex: 1,padding: 16,},header: {alignItems: 'center',marginBottom: 24,},title: {fontSize: 24,fontWeight: 'bold',},versionText: {fontSize: 14,color: '#f00',marginTop: 4,},buttonContainer: {marginBottom: 20,},statusContainer: {flexDirection: 'row',alignItems: 'center',justifyContent: 'center',marginBottom: 20,minHeight: 30,},loader: {marginRight: 10,},statusText: {fontSize: 16,color: '#333',},resultContainer: {flex: 1,borderWidth: 1,borderColor: '#DDD',borderRadius: 8,padding: 10,backgroundColor: '#FFFFFF',},resultTitle: {fontSize: 18,fontWeight: '600',marginBottom: 8,borderBottomWidth: 1,borderBottomColor: '#EEE',paddingBottom: 8,},resultScrollView: {flex: 1,},resultJson: {fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',fontSize: 12,color: '#000',},imageContainer: {padding: 10,borderBottomWidth: 1,borderBottomColor: '#EEE',alignItems: 'center',},imageLabel: {fontSize: 14,fontWeight: '500',alignSelf: 'flex-start',marginBottom: 8,},livenessImage: {width: 200,height: 200,resizeMode: 'contain',borderWidth: 1,borderColor: '#DDD',},});
See Error Code