react-native-vision-camera-spoof-detector 1.0.27 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +54 -27
  2. package/android/build.gradle +3 -5
  3. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofModule.kt +55 -0
  4. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofPackage.kt +2 -24
  5. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +58 -1
  6. package/index.d.ts +14 -1
  7. package/index.js +39 -51
  8. package/package.json +4 -7
  9. package/react-native-vision-camera-spoof-detector.podspec +4 -4
  10. package/.gitattributes +0 -2
  11. package/.npmignore +0 -99
  12. package/CONTRIBUTING.md +0 -280
  13. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  14. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  15. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  16. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  17. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  18. package/android/.gradle/8.9/gc.properties +0 -0
  19. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  20. package/android/.gradle/9.2.0/checksums/md5-checksums.bin +0 -0
  21. package/android/.gradle/9.2.0/checksums/sha1-checksums.bin +0 -0
  22. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  23. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  24. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  25. package/android/.gradle/9.2.0/gc.properties +0 -0
  26. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  27. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  28. package/android/.gradle/vcs-1/gc.properties +0 -0
  29. package/android/build/reports/problems/problems-report.html +0 -659
  30. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofFrameProcessor.kt +0 -198
package/README.md CHANGED
@@ -20,9 +20,11 @@ High-performance face anti-spoofing and liveness detection module for React Nati
20
20
  ## 📋 Requirements
21
21
 
22
22
  - React Native >= 0.60.0
23
- - react-native-vision-camera >= 4.6.4
24
- - react-native-reanimated >= 3.0.0
25
- - react-native-worklets-core >= 1.0.0
23
+ - React Native Vision Camera `^4.6.4` or `^5.0.0`
24
+ - `react-native-reanimated` `^3.0.0`
25
+ - `react-native-worklets` `^0.12.0`
26
+ - `react-native-vision-camera-worklets` `^5.0.0`
27
+ - iOS 11.0 or later
26
28
  - react-native-vision-camera-face-detector (optional, for enhanced features)
27
29
 
28
30
  ## 📦 Installation
@@ -38,12 +40,31 @@ yarn add react-native-vision-camera-spoof-detector
38
40
  ### Step 2: Install peer dependencies
39
41
 
40
42
  ```bash
41
- npm install react-native-vision-camera react-native-reanimated react-native-worklets-core
43
+ npm install react-native-vision-camera react-native-reanimated react-native-worklets react-native-vision-camera-worklets
42
44
  # or
43
- yarn add react-native-vision-camera react-native-reanimated react-native-worklets-core
45
+ yarn add react-native-vision-camera react-native-reanimated react-native-worklets react-native-vision-camera-worklets
44
46
  ```
45
47
 
46
- ### Step 3: Configure Android (if not auto-linked)
48
+ ### Step 3: Configure iOS
49
+
50
+ Install the CocoaPods dependencies from the iOS directory:
51
+
52
+ ```bash
53
+ cd ios
54
+ pod install
55
+ cd ..
56
+ ```
57
+
58
+ Add a camera usage description to `ios/<YourApp>/Info.plist`:
59
+
60
+ ```xml
61
+ <key>NSCameraUsageDescription</key>
62
+ <string>This app uses the camera for face liveness verification.</string>
63
+ ```
64
+
65
+ Open the generated `.xcworkspace` in Xcode, or run the app with the React Native CLI. The package pod bundles `FaceAntiSpoofing.tflite` and declares its `TensorFlowLiteSwift` and `VisionCamera` dependencies automatically. No manual model copy is required.
66
+
67
+ ### Step 4: Configure Android (if not auto-linked)
47
68
 
48
69
  Add to `android/app/build.gradle`:
49
70
 
@@ -53,7 +74,7 @@ dependencies {
53
74
  }
54
75
  ```
55
76
 
56
- ### Step 4: Link native module (for React Native < 0.60)
77
+ ### Step 5: Link native module (for React Native < 0.60)
57
78
 
58
79
  ```bash
59
80
  react-native link react-native-vision-camera-spoof-detector
@@ -61,24 +82,31 @@ react-native link react-native-vision-camera-spoof-detector
61
82
 
62
83
  ## 🚀 Quick Start
63
84
 
85
+ > **Important:** Request camera permission before rendering `Camera`, and call `initializeFaceAntiSpoof()` once before the frame processor starts. The frame processor returns `null` until native initialization or a result is available. Native inference is throttled and may return the most recent result while another frame is being processed.
86
+
64
87
  ### Simple Usage
65
88
 
66
89
  ```javascript
67
90
  import React, { useEffect, useState } from 'react';
68
91
  import { StyleSheet, Text, View } from 'react-native';
69
- import { Camera, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
92
+ import { Camera, useCameraDevices, useCameraPermission, useFrameProcessor } from 'react-native-vision-camera';
70
93
  import { faceAntiSpoofFrameProcessor, initializeFaceAntiSpoof } from 'react-native-vision-camera-spoof-detector';
71
94
  import { runOnJS } from 'react-native-reanimated';
72
95
 
73
96
  export default function App() {
74
97
  const devices = useCameraDevices();
75
98
  const device = devices.front;
99
+ const { hasPermission, requestPermission } = useCameraPermission();
76
100
  const [spoofResult, setSpoofResult] = useState(null);
77
101
 
78
102
  useEffect(() => {
79
- initializeFaceAntiSpoof().then((success) => {
80
- console.log('FaceAntiSpoof initialized:', success);
81
- });
103
+ if (!hasPermission) requestPermission();
104
+ }, [hasPermission, requestPermission]);
105
+
106
+ useEffect(() => {
107
+ initializeFaceAntiSpoof()
108
+ .then((success) => console.log('FaceAntiSpoof initialized:', success))
109
+ .catch((error) => console.error('FaceAntiSpoof initialization failed:', error));
82
110
  }, []);
83
111
 
84
112
  const frameProcessor = useFrameProcessor((frame) => {
@@ -89,7 +117,7 @@ export default function App() {
89
117
  }
90
118
  }, []);
91
119
 
92
- if (device == null) return <Text>Loading...</Text>;
120
+ if (!hasPermission || device == null) return <Text>Waiting for camera permission...</Text>;
93
121
 
94
122
  return (
95
123
  <View style={styles.container}>
@@ -140,7 +168,7 @@ const styles = StyleSheet.create({
140
168
 
141
169
  ```javascript
142
170
  import { useCallback, useMemo, useEffect, useRef } from 'react';
143
- import { Worklets } from 'react-native-worklets-core';
171
+ import { scheduleOnRN } from 'react-native-worklets';
144
172
  import { useFrameProcessor } from 'react-native-vision-camera';
145
173
  import { useFaceDetector } from 'react-native-vision-camera-face-detector';
146
174
  import {
@@ -292,14 +320,14 @@ const result = faceAntiSpoofFrameProcessor(frame);
292
320
 
293
321
  **Parameters**: `frame` (Vision Camera Frame)
294
322
 
295
- **Returns**: `FaceAntiSpoofingResult | null`
323
+ **Returns**: `FaceAntiSpoofingResult | null`. On iOS, inference runs off the frame callback and the returned object can be the latest completed result.
296
324
 
297
325
  ### `FaceAntiSpoofingResult`
298
326
 
299
327
  ```typescript
300
328
  interface FaceAntiSpoofingResult {
301
329
  isLive: boolean; // Real face (true) or spoof (false)
302
- label: string; // "Live Face" or "Spoof Face"
330
+ label: string; // Usually "live", "spoof", or "error"
303
331
  neuralNetworkScore: number; // 0.0-1.0 confidence
304
332
  laplacianScore: number; // Image quality score
305
333
  combinedScore: number; // Weighted average
@@ -331,11 +359,7 @@ const FACE_CENTER_THRESHOLD_Y = 0.15; // Y-axis tolerance
331
359
 
332
360
  ## 🎮 Complete Examples
333
361
 
334
- Check the [examples](./examples) folder for:
335
- - Basic anti-spoofing detection
336
- - Face detection with liveness
337
- - Complete capture flow
338
- - UI components and feedback
362
+ The [Quick Start](#-quick-start) above shows the basic frame-processor integration. For the complete capture flow, face detection, liveness, and UI patterns, see the [project wiki](https://github.com/dpraful/react-native-vision-camera-spoof-detector/wiki).
339
363
 
340
364
  ## 🔍 Attack Detection Capabilities
341
365
 
@@ -363,8 +387,8 @@ Performance depends on:
363
387
 
364
388
  | Platform | Status | GPU | Notes |
365
389
  |----------|--------|-----|-------|
366
- | Android | ✅ Supported | Yes | Fully optimized |
367
- | iOS | In Progress | Yes | Coming soon |
390
+ | Android | ✅ Supported | Yes | TensorFlow Lite model bundled in the AAR |
391
+ | iOS | Supported | CPU | Requires CocoaPods and iOS 11+ |
368
392
  | Web | ❌ No | N/A | Not applicable |
369
393
 
370
394
  ## 🐛 Troubleshooting
@@ -377,11 +401,15 @@ if (!available) {
377
401
  }
378
402
  ```
379
403
 
404
+ - iOS: run `pod install` from the `ios` directory and rebuild the app from the generated workspace.
405
+ - iOS: verify `NSCameraUsageDescription` exists in the app's `Info.plist`.
406
+ - Check the initialization promise result and inspect the native logs for model-loading errors.
407
+
380
408
  **Low accuracy**
381
409
  - Check lighting conditions
382
410
  - Ensure face is centered
383
411
  - Adjust `antispooflevel` parameter
384
- - Verify TensorFlow Lite models are bundled
412
+ - Verify the `FaceAntiSpoofing.tflite` model is bundled (the package does this automatically on iOS)
385
413
 
386
414
  **Performance issues**
387
415
  - Reduce frame processing frequency
@@ -397,10 +425,9 @@ if (!available) {
397
425
 
398
426
  ## 📖 Documentation
399
427
 
400
- - [Complete API Documentation](./.docs/API.md)
401
- - [Migration Guide](./.docs/MIGRATION.md)
402
- - [Best Practices](./.docs/BEST_PRACTICES.md)
403
- - [Comprehensive Example](./examples/CompleteExampleApp.tsx)
428
+ - [Project Wiki](https://github.com/dpraful/react-native-vision-camera-spoof-detector/wiki)
429
+ - [Changelog](./CHANGELOG.md)
430
+ - [Contributing Guide](./CONTRIBUTING.md)
404
431
 
405
432
  ## 🤝 Contributing
406
433
 
@@ -130,10 +130,8 @@ dependencies {
130
130
  // AndroidX - EXIF Support for image orientation
131
131
  implementation "androidx.exifinterface:exifinterface:1.3.6"
132
132
 
133
- // Vision Camera + Worklets
133
+ // VisionCamera 5 uses Nitro frame outputs backed by react-native-worklets.
134
134
  implementation project(':react-native-vision-camera')
135
- implementation project(':react-native-worklets-core')
136
-
137
- // Optional: Face Detector if needed
138
- implementation project(':react-native-vision-camera-face-detector')
135
+ implementation project(':react-native-vision-camera-worklets')
136
+ implementation project(':react-native-worklets')
139
137
  }
@@ -4,6 +4,8 @@ import com.facebook.react.bridge.ReactApplicationContext
4
4
  import com.facebook.react.bridge.ReactContextBaseJavaModule
5
5
  import com.facebook.react.bridge.ReactMethod
6
6
  import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.Arguments
8
+ import com.facebook.react.bridge.ReadableArray
7
9
  import com.facebook.react.module.annotations.ReactModule
8
10
 
9
11
  @ReactModule(name = FaceAntiSpoofModule.NAME)
@@ -126,6 +128,59 @@ class FaceAntiSpoofModule(reactContext: ReactApplicationContext) : ReactContextB
126
128
  }
127
129
  }
128
130
 
131
+ @ReactMethod
132
+ fun processFrame(
133
+ frameData: ReadableArray,
134
+ width: Int,
135
+ height: Int,
136
+ rowStrides: ReadableArray,
137
+ pixelStrides: ReadableArray,
138
+ promise: Promise
139
+ ) {
140
+ try {
141
+ if (frameData.size() < 3 || rowStrides.size() < 3 || pixelStrides.size() < 3) {
142
+ promise.reject("INVALID_FRAME", "Expected Y, U and V camera planes")
143
+ return
144
+ }
145
+
146
+ if (!isModuleInitialized || faceAntiSpoofing == null) {
147
+ promise.reject("NOT_INITIALIZED", "Face anti-spoofing is not initialized")
148
+ return
149
+ }
150
+
151
+ val planes = Array(3) { planeIndex ->
152
+ val plane = frameData.getArray(planeIndex)
153
+ ?: throw IllegalArgumentException("Camera plane $planeIndex is null")
154
+ ByteArray(plane.size()) { index -> plane.getInt(index).toByte() }
155
+ }
156
+ val yuvRowStrides = IntArray(3) { rowStrides.getDouble(it).toInt() }
157
+ val yuvPixelStrides = IntArray(3) { pixelStrides.getDouble(it).toInt().coerceAtLeast(1) }
158
+ val result = faceAntiSpoofing!!.advancedAntiSpoofing(
159
+ planes,
160
+ width,
161
+ height,
162
+ yuvRowStrides,
163
+ yuvPixelStrides
164
+ )
165
+ val isLive = result.neuralNetworkScore < FaceAntiSpoofingAdvanced.BASE_THRESHOLD &&
166
+ result.laplacianScore > FaceAntiSpoofingAdvanced.LAPLACIAN_THRESHOLD
167
+ promise.resolve(
168
+ Arguments.makeNativeMap(
169
+ mapOf(
170
+ "isLive" to isLive,
171
+ "label" to if (isLive) "Live Face" else "Spoof Face",
172
+ "neuralNetworkScore" to result.neuralNetworkScore.toDouble(),
173
+ "laplacianScore" to result.laplacianScore,
174
+ "combinedScore" to result.combinedScore.toDouble(),
175
+ "confidence" to result.confidence.toDouble()
176
+ )
177
+ )
178
+ )
179
+ } catch (e: Exception) {
180
+ promise.reject("PROCESS_ERROR", "Failed to process camera frame", e)
181
+ }
182
+ }
183
+
129
184
  @ReactMethod
130
185
  fun isAvailable(promise: Promise) {
131
186
  try {
@@ -4,32 +4,10 @@ import com.facebook.react.ReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.uimanager.ViewManager
7
- import com.mrousavy.camera.frameprocessors.FrameProcessorPluginRegistry
8
7
 
9
8
  class FaceAntiSpoofPackage : ReactPackage {
10
-
11
- companion object {
12
- init {
13
- try {
14
- FrameProcessorPluginRegistry.addFrameProcessorPlugin("faceAntiSpoof") { proxy, options ->
15
- val plugin = FaceAntiSpoofFrameProcessor()
16
- try {
17
- plugin.initialize(proxy.context.assets)
18
- } catch (e: Exception) {
19
- android.util.Log.e("FaceAntiSpoof", "Failed to initialize plugin with assets", e)
20
- }
21
- plugin
22
- }
23
- } catch (e: Exception) {
24
- android.util.Log.e("FaceAntiSpoof", "Plugin already registered or failed: ${e.message}", e)
25
- }
26
- }
27
- }
28
-
29
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
30
- // Only return the module — DO NOT register plugin here.
31
- return listOf(FaceAntiSpoofModule(reactContext))
32
- }
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
10
+ listOf(FaceAntiSpoofModule(reactContext))
33
11
 
34
12
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
35
13
  return emptyList()
@@ -24,7 +24,7 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
24
24
  const val BASE_THRESHOLD = 0.2f
25
25
  const val ROUTE_INDEX = 6
26
26
  const val LAPLACE_THRESHOLD = 50
27
- const val LAPLACIAN_THRESHOLD = 4000 // Increased from 1000 - real faces have ~3500+ laplacian score
27
+ const val LAPLACIAN_THRESHOLD = 1000
28
28
  const val MODEL_FILE = "FaceAntiSpoofing.tflite"
29
29
  private const val TAG = "FaceAntiSpoofing"
30
30
 
@@ -165,6 +165,25 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
165
165
  }
166
166
  }
167
167
 
168
+ fun advancedAntiSpoofing(
169
+ planes: Array<ByteArray>,
170
+ width: Int,
171
+ height: Int,
172
+ rowStrides: IntArray,
173
+ pixelStrides: IntArray
174
+ ): AntiSpoofingResult {
175
+ if (planes.size < 3) {
176
+ throw IllegalArgumentException("Expected Y, U and V planes")
177
+ }
178
+
179
+ val bitmap = yuv420ToBitmap(planes, width, height, rowStrides, pixelStrides)
180
+ return try {
181
+ runBlocking { advancedAntiSpoofing(bitmap).getOrThrow() }
182
+ } finally {
183
+ bitmap.recycle()
184
+ }
185
+ }
186
+
168
187
  // FROM WORKING VERSION: neuralNetworkAntiSpoofing with Bitmap
169
188
  private fun neuralNetworkAntiSpoofing(bitmap: Bitmap): Result<Float> {
170
189
  return try {
@@ -365,6 +384,44 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
365
384
  return bitmap
366
385
  }
367
386
 
387
+ private fun yuv420ToBitmap(
388
+ planes: Array<ByteArray>,
389
+ width: Int,
390
+ height: Int,
391
+ rowStrides: IntArray,
392
+ pixelStrides: IntArray
393
+ ): Bitmap {
394
+ val pixels = IntArray(width * height)
395
+ val yPlane = planes[0]
396
+ val uPlane = planes[1]
397
+ val vPlane = planes[2]
398
+
399
+ fun sample(plane: ByteArray, row: Int, column: Int, rowStride: Int, pixelStride: Int): Int {
400
+ val index = row * rowStride + column * pixelStride
401
+ return if (index in plane.indices) plane[index].toInt() and 0xFF else 128
402
+ }
403
+
404
+ for (y in 0 until height) {
405
+ for (x in 0 until width) {
406
+ val yValue = sample(yPlane, y, x, rowStrides[0], pixelStrides[0])
407
+ val chromaRow = y / 2
408
+ val chromaColumn = x / 2
409
+ val uValue = sample(uPlane, chromaRow, chromaColumn, rowStrides[1], pixelStrides[1]) - 128
410
+ val vValue = sample(vPlane, chromaRow, chromaColumn, rowStrides[2], pixelStrides[2]) - 128
411
+
412
+ val red = (yValue + 1.402f * vValue).coerceIn(0f, 255f).toInt()
413
+ val green = (yValue - 0.344f * uValue - 0.714f * vValue).coerceIn(0f, 255f).toInt()
414
+ val blue = (yValue + 1.772f * uValue).coerceIn(0f, 255f).toInt()
415
+ pixels[y * width + x] = (0xFF shl 24) or
416
+ (red shl 16) or
417
+ (green shl 8) or
418
+ blue
419
+ }
420
+ }
421
+
422
+ return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888)
423
+ }
424
+
368
425
  @Throws(IOException::class)
369
426
  private fun loadModelFile(assetManager: AssetManager, modelName: String): MappedByteBuffer {
370
427
  return try {
package/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * TypeScript type definitions
5
5
  */
6
6
 
7
- import type { Frame, FrameProcessor } from 'react-native-vision-camera';
7
+ import type { CameraFrameOutput, Frame, FrameOutputOptions, FrameProcessor } from 'react-native-vision-camera';
8
8
  import type { SharedValue } from 'react-native-reanimated';
9
9
 
10
10
  // ============================================================================
@@ -281,6 +281,19 @@ export interface UseFaceDetectionFrameProcessorReturn {
281
281
  antiSpoofState: AntiSpoofState;
282
282
  }
283
283
 
284
+ /**
285
+ * VisionCamera 5 frame-output options for spoof detection.
286
+ * The callback runs on the React Native runtime after native inference.
287
+ */
288
+ export interface UseFaceAntiSpoofFrameOutputOptions extends Partial<FrameOutputOptions> {
289
+ onResult?: (result: FaceAntiSpoofingResult) => void;
290
+ }
291
+
292
+ /** Create a VisionCamera 5 frame output backed by the native detector. */
293
+ export function useFaceAntiSpoofFrameOutput(
294
+ options?: UseFaceAntiSpoofFrameOutputOptions,
295
+ ): CameraFrameOutput;
296
+
284
297
  // ============================================================================
285
298
  // Module Functions
286
299
  // ============================================================================
package/index.js CHANGED
@@ -1,60 +1,50 @@
1
1
  import { NativeModules } from 'react-native';
2
- import { VisionCameraProxy } from 'react-native-vision-camera';
2
+ import { useFrameOutput } from 'react-native-vision-camera';
3
+ import { scheduleOnRN } from 'react-native-worklets';
3
4
 
4
5
  const { FaceAntiSpoof } = NativeModules;
5
6
 
6
- // Initialize the plugin before any worklet captures this module.
7
- let _faceAntiSpoofPlugin = null;
8
-
9
- try {
10
- _faceAntiSpoofPlugin = VisionCameraProxy.initFrameProcessorPlugin('faceAntiSpoof', {});
11
- } catch (e) {
12
- console.warn('[FaceAntiSpoof] Failed to init frame processor plugin:', e);
13
- }
7
+ const processFrameOnRN = (frameData, width, height, onResult) => {
8
+ FaceAntiSpoof.processFrame(frameData.planes, width, height, frameData.rowStrides, frameData.pixelStrides)
9
+ .then(onResult)
10
+ .catch((error) => console.error('[FaceAntiSpoof] Frame processing failed:', error));
11
+ };
14
12
 
15
- function ensurePluginInitialized() {
16
- if (!_faceAntiSpoofPlugin) {
13
+ export const useFaceAntiSpoofFrameOutput = ({ onResult, ...options } = {}) => {
14
+ const onFrame = (frame) => {
15
+ 'worklet';
17
16
  try {
18
- _faceAntiSpoofPlugin = VisionCameraProxy.initFrameProcessorPlugin('faceAntiSpoof', {});
19
- } catch (e) {
20
- console.warn('[FaceAntiSpoof] Failed to init frame processor plugin:', e);
21
- _faceAntiSpoofPlugin = null;
17
+ const planes = frame.getPlanes();
18
+ if (planes.length < 3) return;
19
+
20
+ const planeData = planes.map((plane) => Array.from(new Uint8Array(plane.getPixelBuffer())));
21
+ const rowStrides = planes.map((plane) => plane.bytesPerRow);
22
+ const pixelStrides = planes.map((plane) => plane.bytesPerRow / plane.width);
23
+ scheduleOnRN(
24
+ processFrameOnRN,
25
+ { planes: planeData, rowStrides, pixelStrides },
26
+ frame.width,
27
+ frame.height,
28
+ onResult,
29
+ );
30
+ } finally {
31
+ frame.dispose();
22
32
  }
23
- }
24
- return !!_faceAntiSpoofPlugin;
25
- }
33
+ };
26
34
 
27
- // Worklet called by VisionCamera
28
- export const faceAntiSpoofFrameProcessor = function (frame) {
35
+ return useFrameOutput({
36
+ ...options,
37
+ pixelFormat: 'yuv',
38
+ targetResolution: { width: 256, height: 256 },
39
+ onFrame,
40
+ });
41
+ };
42
+
43
+ // Kept as a named export for source compatibility. VisionCamera 5 applications
44
+ // must use useFaceAntiSpoofFrameOutput because the old plugin API was removed.
45
+ export const faceAntiSpoofFrameProcessor = function () {
29
46
  'worklet';
30
- try {
31
- if (!_faceAntiSpoofPlugin) {
32
- console.warn('[FaceAntiSpoof] Plugin not initialized');
33
- return null;
34
- }
35
-
36
- if (typeof _faceAntiSpoofPlugin.call !== 'function') {
37
- console.warn('[FaceAntiSpoof] Plugin call method not available');
38
- return null;
39
- }
40
-
41
- if (!frame) {
42
- console.warn('[FaceAntiSpoof] Frame is null or undefined');
43
- return null;
44
- }
45
-
46
- const result = _faceAntiSpoofPlugin.call(frame);
47
-
48
- // Validate result structure
49
- if (result && typeof result === 'object') {
50
- return result;
51
- }
52
-
53
- return null;
54
- } catch (err) {
55
- console.error('[FaceAntiSpoof] Error in frame processor:', err);
56
- return null;
57
- }
47
+ return null;
58
48
  };
59
49
 
60
50
  export default FaceAntiSpoof;
@@ -86,9 +76,7 @@ export const initializeFaceAntiSpoof = async () => {
86
76
  }
87
77
 
88
78
  const isSuccess = result && status.pluginAvailable;
89
- // If native initialization succeeded, register the frame processor plugin for worklets
90
- const pluginInitialized = isSuccess ? ensurePluginInitialized() : false;
91
- const initialized = isSuccess && pluginInitialized;
79
+ const initialized = isSuccess;
92
80
  console.log('[FaceAntiSpoof] Initialization result:', initialized);
93
81
  return initialized;
94
82
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-vision-camera-spoof-detector",
3
- "version": "1.0.27",
3
+ "version": "1.1.0",
4
4
  "description": "High-performance face anti-spoofing and liveness detection module for React Native Vision Camera. Uses TensorFlow Lite with GPU acceleration and optimized YUV processing.",
5
5
  "homepage": "https://github.com/dpraful/react-native-vision-camera-spoof-detector",
6
6
  "repository": {
@@ -10,7 +10,7 @@
10
10
  "bugs": {
11
11
  "url": "https://github.com/dpraful/react-native-vision-camera-spoof-detector/issues"
12
12
  },
13
- "license": "JSCON TECHNOLOGIES PVT LTD",
13
+ "license": "MIT",
14
14
  "author": {
15
15
  "name": "PRAFULDAS M M",
16
16
  "company": "JESCON TECHNOLOGIES PVT LTD",
@@ -29,11 +29,7 @@
29
29
  "files": [
30
30
  "android/",
31
31
  "ios/",
32
- ".gitattributes",
33
- ".gitignore",
34
- ".npmignore",
35
32
  "CHANGELOG.md",
36
- "CONTRIBUTING.md",
37
33
  "index.js",
38
34
  "index.d.ts",
39
35
  "README.md",
@@ -62,7 +58,8 @@
62
58
  "react-native": ">=0.60.0",
63
59
  "react-native-vision-camera": "^4.6.4 || ^5.0.0",
64
60
  "react-native-reanimated": "^3.0.0",
65
- "react-native-worklets-core": "^1.0.0"
61
+ "react-native-vision-camera-worklets": "^5.0.0",
62
+ "react-native-worklets": "^0.12.0"
66
63
  },
67
64
  "peerDependenciesMeta": {
68
65
  "react-native-vision-camera-face-detector": {
@@ -1,10 +1,10 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'react-native-vision-camera-spoof-detector'
3
- s.version = '0.1.0'
3
+ s.version = '1.1.0'
4
4
  s.summary = 'Face anti-spoof detector for VisionCamera (iOS)'
5
- s.homepage = 'https://example.com'
6
- s.license = { :type => 'MIT' }
7
- s.authors = { 'You' => 'you@example.com' }
5
+ s.homepage = 'https://github.com/dpraful/react-native-vision-camera-spoof-detector'
6
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
7
+ s.authors = { 'JESCON TECHNOLOGIES PVT LTD' => 'jescontechnologies@gmail.com' }
8
8
  s.platform = :ios, '11.0'
9
9
  s.source = { :path => '.' }
10
10
 
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
package/.npmignore DELETED
@@ -1,99 +0,0 @@
1
- # npm ignore patterns - files that should not be published to npm
2
-
3
- # Development files
4
- .git
5
- .gitignore
6
- .gitattributes
7
-
8
- # Development dependencies
9
- node_modules
10
- npm-debug.log*
11
- yarn-debug.log*
12
- yarn-error.log*
13
-
14
- # IDE / Editor files
15
- .vscode
16
- .idea
17
- .DS_Store
18
- *.swp
19
- *.swo
20
- *~
21
- .env
22
- .env.local
23
-
24
- # Build artifacts and temporary files
25
- build/
26
- dist/
27
- .rollup.cache/
28
- .eslintcache
29
- *.tsbuildinfo
30
-
31
- # Android build artifacts and caches
32
- android/build/
33
- android/.gradle/
34
- android/.kotlin/
35
- android/*.log
36
- *.apk
37
- *.aar
38
- *.so
39
-
40
- # Testing
41
- __tests__
42
- __mocks__
43
- *.test.ts
44
- *.test.tsx
45
- *.spec.ts
46
- *.spec.tsx
47
- coverage
48
- .jest
49
-
50
- # Documentation (optional - remove if you want to publish docs)
51
- docs/*.md
52
- .docs/
53
-
54
- # Example files (optional - remove if you want to include examples)
55
- example/
56
- examples/
57
- demo/
58
-
59
- # CI/CD
60
- .github/workflows
61
- .gitlab-ci.yml
62
- .travis.yml
63
- azure-pipelines.yml
64
-
65
- # Root level files
66
- .prettierrc
67
- .prettierignore
68
- .eslintrc
69
- .eslintignore
70
- .babelrc
71
- tsconfig.json
72
- jest.config.js
73
- babel.config.js
74
- webpack.config.js
75
- Makefile
76
-
77
- # Contribution files
78
- CONTRIBUTING.md
79
- CODE_OF_CONDUCT.md
80
- PULL_REQUEST_TEMPLATE.md
81
-
82
- # Misc
83
- *.map
84
- .npmrc
85
- .yarnrc
86
- .DS_Store
87
- Thumbs.db
88
- *.lock
89
- package-lock.json
90
- yarn.lock
91
-
92
- # Keep essential files
93
- !android/
94
- !index.js
95
- !index.d.ts
96
- !README.md
97
- !CHANGELOG.md
98
- !LICENSE
99
- !package.json