@cleanuidev/react-native-scanner 1.0.0-beta.2 → 1.0.0-beta.3
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.
- package/README.md +72 -28
- package/android/src/main/java/com/scanner/ScannerView.kt +58 -2
- package/android/src/main/java/com/scanner/ScannerViewManager.kt +63 -30
- package/ios/ScannerView.mm +5 -1
- package/lib/module/ScannerViewNativeComponent.ts +2 -1
- package/lib/typescript/src/ScannerViewNativeComponent.d.ts +2 -2
- package/lib/typescript/src/ScannerViewNativeComponent.d.ts.map +1 -1
- package/package.json +27 -3
- package/src/ScannerViewNativeComponent.ts +2 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# 📱 React Native Scanner
|
|
4
4
|
|
|
5
|
-
**A powerful, native barcode and QR code scanner for React Native**
|
|
5
|
+
**A powerful, native barcode and QR code scanner for React Native with configurable target area scanning**
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@cleanuidev/react-native-scanner)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
| Feature | Description |
|
|
27
27
|
|:------:|:-----------|
|
|
28
28
|
| 🚀 **Native Performance** | Built with CameraX & ML Kit (Android) and AVFoundation & Vision (iOS) for optimal performance |
|
|
29
|
-
| 🎯 **
|
|
29
|
+
| 🎯 **Target Area Scanning** | Scan barcodes within configurable target areas for precise detection |
|
|
30
30
|
| 🔦 **Torch Control** | Built-in flashlight/torch control |
|
|
31
31
|
| 📊 **Multiple Formats** | Support for QR codes, Code128, Code39, EAN, UPC, and more |
|
|
32
|
-
| 🎨 **Customizable** | Configurable
|
|
32
|
+
| 🎨 **Customizable** | Configurable target area colors, barcode frame visualization, and scanning behavior |
|
|
33
33
|
| 📱 **Cross Platform** | Android & iOS support (new Fabric architecture) |
|
|
34
34
|
|
|
35
35
|
</div>
|
|
@@ -129,7 +129,7 @@ const styles = StyleSheet.create({
|
|
|
129
129
|
});
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
### Scanner with
|
|
132
|
+
### Scanner with Target Area
|
|
133
133
|
|
|
134
134
|
```tsx
|
|
135
135
|
import React, { useState } from 'react';
|
|
@@ -139,12 +139,12 @@ import ScannerView, { BarcodeFormat } from '@cleanuidev/react-native-scanner';
|
|
|
139
139
|
export default function FocusAreaScanner() {
|
|
140
140
|
const [torchEnabled, setTorchEnabled] = useState(false);
|
|
141
141
|
|
|
142
|
-
//
|
|
142
|
+
// Target area configuration
|
|
143
143
|
const focusAreaConfig = {
|
|
144
|
-
enabled: true, // Only scan barcodes within the
|
|
145
|
-
showOverlay: true, // Show the
|
|
146
|
-
size: 300, // Size of the
|
|
147
|
-
color: '#00FF00', // Color of the
|
|
144
|
+
enabled: true, // Only scan barcodes within the target area
|
|
145
|
+
showOverlay: true, // Show overlay outside the target area
|
|
146
|
+
size: 300, // Size of the target area (square)
|
|
147
|
+
color: '#00FF00', // Color of the target area border
|
|
148
148
|
};
|
|
149
149
|
|
|
150
150
|
// Barcode frames configuration
|
|
@@ -198,7 +198,7 @@ export default function FocusAreaScanner() {
|
|
|
198
198
|
| Prop | Type | Default | Description |
|
|
199
199
|
|------|------|---------|-------------|
|
|
200
200
|
| `barcodeTypes` | `BarcodeFormat[]` | `[BarcodeFormat.QR_CODE]` | Array of barcode formats to scan |
|
|
201
|
-
| `focusArea` | `FocusAreaConfig` | - |
|
|
201
|
+
| `focusArea` | `FocusAreaConfig` | - | Target area configuration for precise scanning |
|
|
202
202
|
| `barcodeFrames` | `BarcodeFramesConfig` | - | Barcode frame visualization configuration |
|
|
203
203
|
| `torch` | `boolean` | `false` | Enable/disable torch/flashlight |
|
|
204
204
|
| `zoom` | `number` | `1.0` | Camera zoom level |
|
|
@@ -213,10 +213,10 @@ export default function FocusAreaScanner() {
|
|
|
213
213
|
|
|
214
214
|
```tsx
|
|
215
215
|
type FocusAreaConfig = {
|
|
216
|
-
enabled?: boolean; // Whether to restrict scanning to
|
|
217
|
-
size?: FrameSize; // Size of the
|
|
218
|
-
color?: string; // Color of
|
|
219
|
-
showOverlay?: boolean; // Whether to draw the
|
|
216
|
+
enabled?: boolean; // Whether to restrict scanning to target area only
|
|
217
|
+
size?: FrameSize; // Size of the target area
|
|
218
|
+
color?: string; // Color of target area border
|
|
219
|
+
showOverlay?: boolean; // Whether to draw overlay outside the target area
|
|
220
220
|
};
|
|
221
221
|
```
|
|
222
222
|
|
|
@@ -226,7 +226,7 @@ type FocusAreaConfig = {
|
|
|
226
226
|
type BarcodeFramesConfig = {
|
|
227
227
|
enabled?: boolean; // Whether to draw frames around detected barcodes
|
|
228
228
|
color?: string; // Color of barcode frames
|
|
229
|
-
onlyInFocusArea?: boolean; // Only show frames for barcodes in
|
|
229
|
+
onlyInFocusArea?: boolean; // Only show frames for barcodes in target area
|
|
230
230
|
};
|
|
231
231
|
```
|
|
232
232
|
|
|
@@ -311,16 +311,16 @@ BarcodeFormat.ITF // ITF (Interleaved 2 of 5)
|
|
|
311
311
|
}
|
|
312
312
|
```
|
|
313
313
|
|
|
314
|
-
##
|
|
314
|
+
## Target Area Configuration
|
|
315
315
|
|
|
316
|
-
The
|
|
316
|
+
The target area feature provides precise control over where barcodes are scanned:
|
|
317
317
|
|
|
318
|
-
### Basic
|
|
318
|
+
### Basic Target Area
|
|
319
319
|
|
|
320
320
|
```tsx
|
|
321
321
|
<ScannerView
|
|
322
322
|
focusArea={{
|
|
323
|
-
showOverlay: true, // Show
|
|
323
|
+
showOverlay: true, // Show overlay outside the target area
|
|
324
324
|
size: 300, // 300x300 pixel square
|
|
325
325
|
color: '#00FF00', // Green border
|
|
326
326
|
}}
|
|
@@ -328,33 +328,64 @@ The focus area feature provides precise control over where barcodes are scanned:
|
|
|
328
328
|
/>
|
|
329
329
|
```
|
|
330
330
|
|
|
331
|
-
###
|
|
331
|
+
### Target Area with Restricted Scanning
|
|
332
332
|
|
|
333
333
|
```tsx
|
|
334
334
|
<ScannerView
|
|
335
335
|
focusArea={{
|
|
336
|
-
enabled: true, // Only scan within
|
|
337
|
-
showOverlay: true, // Show
|
|
336
|
+
enabled: true, // Only scan within target area
|
|
337
|
+
showOverlay: true, // Show overlay outside the target area
|
|
338
338
|
size: 300, // 300x300 pixel square
|
|
339
339
|
color: '#00FF00', // Green border
|
|
340
340
|
}}
|
|
341
|
-
// Only scans within the
|
|
341
|
+
// Only scans within the target area
|
|
342
342
|
/>
|
|
343
343
|
```
|
|
344
344
|
|
|
345
|
-
### Rectangular
|
|
345
|
+
### Rectangular Target Area
|
|
346
346
|
|
|
347
347
|
```tsx
|
|
348
348
|
<ScannerView
|
|
349
349
|
focusArea={{
|
|
350
350
|
enabled: true,
|
|
351
351
|
showOverlay: true,
|
|
352
|
-
size: { width: 300, height: 200 }, // Rectangular
|
|
352
|
+
size: { width: 300, height: 200 }, // Rectangular target area
|
|
353
353
|
color: '#00FF00',
|
|
354
354
|
}}
|
|
355
355
|
/>
|
|
356
356
|
```
|
|
357
357
|
|
|
358
|
+
### Positioning Target Area with Coordinates
|
|
359
|
+
|
|
360
|
+
You can position the target area anywhere on the screen using percentage-based coordinates (0-100):
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
<ScannerView
|
|
364
|
+
focusArea={{
|
|
365
|
+
enabled: true,
|
|
366
|
+
showOverlay: true,
|
|
367
|
+
size: 300,
|
|
368
|
+
position: { x: 50, y: 50 }, // Center position (default)
|
|
369
|
+
color: '#00FF00',
|
|
370
|
+
}}
|
|
371
|
+
/>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Example: Position target area at top center**
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
<ScannerView
|
|
378
|
+
focusArea={{
|
|
379
|
+
enabled: true,
|
|
380
|
+
showOverlay: true,
|
|
381
|
+
size: 250,
|
|
382
|
+
position: { x: 50, y: 25 }, // Top center
|
|
383
|
+
color: '#00FF00',
|
|
384
|
+
}}
|
|
385
|
+
onBarcodeScanned={handleBarcodeScanned}
|
|
386
|
+
/>
|
|
387
|
+
```
|
|
388
|
+
|
|
358
389
|
## Barcode Frame Visualization
|
|
359
390
|
|
|
360
391
|
The scanner can display visual frames around detected barcodes to help users see what's being scanned:
|
|
@@ -371,7 +402,7 @@ The scanner can display visual frames around detected barcodes to help users see
|
|
|
371
402
|
/>
|
|
372
403
|
```
|
|
373
404
|
|
|
374
|
-
### Show Frames Only in
|
|
405
|
+
### Show Frames Only in Target Area
|
|
375
406
|
|
|
376
407
|
```tsx
|
|
377
408
|
<ScannerView
|
|
@@ -383,7 +414,7 @@ The scanner can display visual frames around detected barcodes to help users see
|
|
|
383
414
|
barcodeFrames={{
|
|
384
415
|
enabled: true,
|
|
385
416
|
color: '#FF0000',
|
|
386
|
-
onlyInFocusArea: true, // Only show frames for barcodes in
|
|
417
|
+
onlyInFocusArea: true, // Only show frames for barcodes in target area
|
|
387
418
|
}}
|
|
388
419
|
/>
|
|
389
420
|
```
|
|
@@ -567,6 +598,19 @@ For bug reports, feature requests, and general questions:
|
|
|
567
598
|
- 📝 [Open an issue](https://github.com/cleanui-dev/react-native-scanner/issues) on GitHub
|
|
568
599
|
- 💬 Use GitHub Discussions for questions and community help
|
|
569
600
|
|
|
601
|
+
### Support the Maintainer
|
|
602
|
+
|
|
603
|
+
If you find this library useful, consider supporting the maintainer/developer directly through donations:
|
|
604
|
+
|
|
605
|
+
- 💰 [Donate via PayPal](https://paypal.me/rahulgwebdev) - Support the maintainer directly and help keep this project maintained and improved
|
|
606
|
+
- ⭐ Star the repository - Show your appreciation and help others discover this library
|
|
607
|
+
|
|
608
|
+
**Your donations help:**
|
|
609
|
+
- 🐛 Maintain and fix bugs
|
|
610
|
+
- ✨ Add new features and improvements
|
|
611
|
+
- 📚 Keep documentation up to date
|
|
612
|
+
- ⚡ Ensure long-term sustainability of the project
|
|
613
|
+
|
|
570
614
|
### Commercial Support & Consulting
|
|
571
615
|
|
|
572
616
|
Need professional help with implementation, custom development, or enterprise support?
|
|
@@ -222,6 +222,7 @@ class ScannerView : FrameLayout {
|
|
|
222
222
|
|
|
223
223
|
if (!hasCameraPermission()) {
|
|
224
224
|
Log.e(TAG, "Camera permission not granted")
|
|
225
|
+
emitOnScannerError("Camera permission not granted", "CAMERA_PERMISSION_DENIED")
|
|
225
226
|
return
|
|
226
227
|
}
|
|
227
228
|
|
|
@@ -331,8 +332,16 @@ class ScannerView : FrameLayout {
|
|
|
331
332
|
// Set up auto-focus on frame center (if focus area is enabled)
|
|
332
333
|
setupAutoFocusOnFrame()
|
|
333
334
|
|
|
335
|
+
// Emit onLoad event after camera is successfully started
|
|
336
|
+
emitOnLoadEvent(success = true)
|
|
337
|
+
|
|
334
338
|
} catch (exc: Exception) {
|
|
335
339
|
Log.e(TAG, "Use case binding failed", exc)
|
|
340
|
+
// Emit onScannerError event for camera initialization failure
|
|
341
|
+
emitOnScannerError(
|
|
342
|
+
error = exc.message ?: "Camera binding failed",
|
|
343
|
+
code = "CAMERA_INITIALIZATION_FAILED"
|
|
344
|
+
)
|
|
336
345
|
}
|
|
337
346
|
}
|
|
338
347
|
|
|
@@ -450,12 +459,14 @@ class ScannerView : FrameLayout {
|
|
|
450
459
|
// Debounce: Prevent rapid duplicate emissions
|
|
451
460
|
// If we've emitted recently (within debounce interval), skip this emission
|
|
452
461
|
// This prevents multiple alerts when pauseScanning is set but detection callbacks are still in flight
|
|
462
|
+
Log.d(TAG, "📊 Debounce check: interval=${barcodeEmissionDebounceInterval}ms, timeSinceLast=${timeSinceLastEmission}ms")
|
|
453
463
|
if (timeSinceLastEmission < barcodeEmissionDebounceInterval) {
|
|
454
|
-
Log.d(TAG, "⏭️ Skipping barcode emission (debounced, last emission was ${timeSinceLastEmission}ms ago)")
|
|
464
|
+
Log.d(TAG, "⏭️ Skipping barcode emission (debounced, last emission was ${timeSinceLastEmission}ms ago, interval=${barcodeEmissionDebounceInterval}ms)")
|
|
455
465
|
return@addOnSuccessListener
|
|
456
466
|
}
|
|
457
467
|
|
|
458
468
|
lastBarcodeEmissionTime = currentTime
|
|
469
|
+
Log.d(TAG, "✅ Emitting barcode (interval=${barcodeEmissionDebounceInterval}ms, timeSinceLast=${timeSinceLastEmission}ms)")
|
|
459
470
|
|
|
460
471
|
// Create array of barcode events
|
|
461
472
|
val barcodeEvents = Arguments.createArray()
|
|
@@ -502,6 +513,11 @@ class ScannerView : FrameLayout {
|
|
|
502
513
|
}
|
|
503
514
|
}
|
|
504
515
|
.addOnFailureListener { e ->
|
|
516
|
+
// Emit onScannerError event for barcode detection failure
|
|
517
|
+
emitOnScannerError(
|
|
518
|
+
error = e.message ?: "Barcode detection failed",
|
|
519
|
+
code = "BARCODE_DETECTION_FAILED"
|
|
520
|
+
)
|
|
505
521
|
Log.e(TAG, "Barcode scanning failed", e)
|
|
506
522
|
}
|
|
507
523
|
.addOnCompleteListener {
|
|
@@ -613,8 +629,48 @@ class ScannerView : FrameLayout {
|
|
|
613
629
|
|
|
614
630
|
fun setBarcodeEmissionInterval(intervalSeconds: Double) {
|
|
615
631
|
// Convert seconds to milliseconds, ensure non-negative
|
|
632
|
+
val previousInterval = barcodeEmissionDebounceInterval
|
|
633
|
+
Log.d(TAG, "📊 [ScannerView] setBarcodeEmissionInterval called with: ${intervalSeconds}s")
|
|
616
634
|
barcodeEmissionDebounceInterval = max(0, (intervalSeconds * 1000).toLong())
|
|
617
|
-
Log.d(TAG, "
|
|
635
|
+
Log.d(TAG, "📊 ScannerView.setBarcodeEmissionInterval: ${intervalSeconds}s -> ${barcodeEmissionDebounceInterval}ms (was ${previousInterval}ms)")
|
|
636
|
+
|
|
637
|
+
if (barcodeEmissionDebounceInterval == 0L) {
|
|
638
|
+
Log.d(TAG, "📊 ⚠️ Debouncing DISABLED (interval = 0ms)")
|
|
639
|
+
} else {
|
|
640
|
+
Log.d(TAG, "📊 ✅ Debouncing ENABLED (interval = ${barcodeEmissionDebounceInterval}ms)")
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
private fun emitOnLoadEvent(success: Boolean, error: String? = null) {
|
|
645
|
+
val ctx = reactContext
|
|
646
|
+
if (ctx is ThemedReactContext) {
|
|
647
|
+
ctx.runOnUiQueueThread {
|
|
648
|
+
val eventData = Arguments.createMap().apply {
|
|
649
|
+
putBoolean("success", success)
|
|
650
|
+
if (error != null) {
|
|
651
|
+
putString("error", error)
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
ctx.getJSModule(RCTEventEmitter::class.java)
|
|
655
|
+
.receiveEvent(this@ScannerView.id, "onLoad", eventData)
|
|
656
|
+
Log.d(TAG, "✅ onLoad event emitted: success=$success, error=$error")
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
private fun emitOnScannerError(error: String, code: String) {
|
|
662
|
+
val ctx = reactContext
|
|
663
|
+
if (ctx is ThemedReactContext) {
|
|
664
|
+
ctx.runOnUiQueueThread {
|
|
665
|
+
val eventData = Arguments.createMap().apply {
|
|
666
|
+
putString("error", error)
|
|
667
|
+
putString("code", code)
|
|
668
|
+
}
|
|
669
|
+
ctx.getJSModule(RCTEventEmitter::class.java)
|
|
670
|
+
.receiveEvent(this@ScannerView.id, "onScannerError", eventData)
|
|
671
|
+
Log.d(TAG, "✅ onScannerError event emitted: code=$code, error=$error")
|
|
672
|
+
}
|
|
673
|
+
}
|
|
618
674
|
}
|
|
619
675
|
|
|
620
676
|
fun setBarcodeScanStrategy(strategy: String) {
|
|
@@ -6,12 +6,20 @@ import com.facebook.react.bridge.*
|
|
|
6
6
|
import com.facebook.react.module.annotations.ReactModule
|
|
7
7
|
import com.facebook.react.uimanager.SimpleViewManager
|
|
8
8
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
9
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
9
10
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
10
11
|
import com.facebook.react.uimanager.events.RCTModernEventEmitter
|
|
12
|
+
import com.facebook.react.viewmanagers.ScannerViewManagerInterface
|
|
13
|
+
import com.facebook.react.viewmanagers.ScannerViewManagerDelegate
|
|
11
14
|
|
|
12
15
|
@ReactModule(name = ScannerViewManager.NAME)
|
|
13
|
-
class ScannerViewManager : SimpleViewManager<ScannerView>()
|
|
16
|
+
class ScannerViewManager : SimpleViewManager<ScannerView>(),
|
|
17
|
+
ScannerViewManagerInterface<ScannerView> {
|
|
18
|
+
private val mDelegate: ViewManagerDelegate<ScannerView> = ScannerViewManagerDelegate(this)
|
|
14
19
|
|
|
20
|
+
override fun getDelegate(): ViewManagerDelegate<ScannerView> {
|
|
21
|
+
return mDelegate
|
|
22
|
+
}
|
|
15
23
|
override fun getName(): String {
|
|
16
24
|
return NAME
|
|
17
25
|
}
|
|
@@ -22,7 +30,7 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
|
|
|
22
30
|
|
|
23
31
|
// Barcode configuration
|
|
24
32
|
@ReactProp(name = "barcodeTypes")
|
|
25
|
-
fun setBarcodeTypes(view: ScannerView?, types: ReadableArray?) {
|
|
33
|
+
override fun setBarcodeTypes(view: ScannerView?, types: ReadableArray?) {
|
|
26
34
|
if (types != null) {
|
|
27
35
|
val typeList = mutableListOf<String>()
|
|
28
36
|
for (i in 0 until types.size()) {
|
|
@@ -36,33 +44,33 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
|
|
|
36
44
|
|
|
37
45
|
// Focus area configuration
|
|
38
46
|
@ReactProp(name = "focusArea")
|
|
39
|
-
fun setFocusArea(view: ScannerView?, focusArea: ReadableMap?) {
|
|
47
|
+
override fun setFocusArea(view: ScannerView?, focusArea: ReadableMap?) {
|
|
40
48
|
if (focusArea != null) {
|
|
41
|
-
val enabled = focusArea.getBoolean("enabled")
|
|
42
|
-
val showOverlay = focusArea.getBoolean("showOverlay")
|
|
49
|
+
val enabled = focusArea.getBoolean("enabled")
|
|
50
|
+
val showOverlay = focusArea.getBoolean("showOverlay")
|
|
43
51
|
val borderColor = focusArea.getString("borderColor")
|
|
44
52
|
val tintColor = focusArea.getString("tintColor")
|
|
45
53
|
val size = focusArea.getDynamic("size")
|
|
46
54
|
val position = focusArea.getMap("position")
|
|
47
|
-
|
|
55
|
+
|
|
48
56
|
// Set focus area properties
|
|
49
57
|
view?.setFocusAreaEnabled(enabled)
|
|
50
58
|
view?.setEnableFrame(showOverlay)
|
|
51
|
-
|
|
59
|
+
|
|
52
60
|
if (borderColor != null) {
|
|
53
61
|
view?.setBorderColor(borderColor)
|
|
54
62
|
}
|
|
55
|
-
|
|
63
|
+
|
|
56
64
|
if (tintColor != null) {
|
|
57
65
|
view?.setTintColor(tintColor)
|
|
58
66
|
}
|
|
59
|
-
|
|
67
|
+
|
|
60
68
|
if (position != null) {
|
|
61
69
|
val x = position.getDouble("x").toFloat()
|
|
62
70
|
val y = position.getDouble("y").toFloat()
|
|
63
71
|
view?.setPosition(x, y)
|
|
64
72
|
}
|
|
65
|
-
|
|
73
|
+
|
|
66
74
|
if (size != null) {
|
|
67
75
|
val frameSize: FrameSize = when {
|
|
68
76
|
size.type == ReadableType.Number -> FrameSize.Square(size.asInt())
|
|
@@ -76,40 +84,40 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
|
|
|
76
84
|
}
|
|
77
85
|
view?.setFrameSize(frameSize)
|
|
78
86
|
}
|
|
79
|
-
|
|
87
|
+
|
|
80
88
|
Log.d("ScannerViewManager", "Focus area configured: enabled=$enabled, showOverlay=$showOverlay, borderColor=$borderColor, tintColor=$tintColor, position=$position")
|
|
81
89
|
}
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
// Barcode frames configuration
|
|
85
93
|
@ReactProp(name = "barcodeFrames")
|
|
86
|
-
fun setBarcodeFrames(view: ScannerView?, barcodeFrames: ReadableMap?) {
|
|
94
|
+
override fun setBarcodeFrames(view: ScannerView?, barcodeFrames: ReadableMap?) {
|
|
87
95
|
if (barcodeFrames != null) {
|
|
88
96
|
val enabled = barcodeFrames.getBoolean("enabled") ?: false
|
|
89
97
|
val color = barcodeFrames.getString("color")
|
|
90
98
|
val onlyInFocusArea = barcodeFrames.getBoolean("onlyInFocusArea") ?: false
|
|
91
|
-
|
|
99
|
+
|
|
92
100
|
// Set barcode frames properties
|
|
93
101
|
view?.setBarcodeFramesEnabled(enabled)
|
|
94
102
|
view?.setShowBarcodeFramesOnlyInFrame(onlyInFocusArea)
|
|
95
|
-
|
|
103
|
+
|
|
96
104
|
if (color != null) {
|
|
97
105
|
view?.setBarcodeFramesColor(color)
|
|
98
106
|
}
|
|
99
|
-
|
|
107
|
+
|
|
100
108
|
Log.d("ScannerViewManager", "Barcode frames configured: enabled=$enabled, onlyInFocusArea=$onlyInFocusArea, color=$color")
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
// Torch control
|
|
105
113
|
@ReactProp(name = "torch")
|
|
106
|
-
fun setTorch(view: ScannerView
|
|
107
|
-
view
|
|
114
|
+
override fun setTorch(view: ScannerView, value: Boolean) {
|
|
115
|
+
view.setTorch(value)
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
// Event handlers
|
|
111
119
|
@ReactProp(name = "onBarcodeScanned")
|
|
112
|
-
|
|
120
|
+
fun setOnBarcodeScanned(view: ScannerView?, onBarcodeScanned: Boolean?) {
|
|
113
121
|
// This prop is used to register the event handler
|
|
114
122
|
// The actual event emission happens in ScannerView.processImage()
|
|
115
123
|
Log.d("ScannerViewManager", "onBarcodeScanned event handler registered")
|
|
@@ -128,33 +136,49 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
|
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
@ReactProp(name = "zoom")
|
|
131
|
-
fun setZoom(view: ScannerView?, zoom: Double) {
|
|
139
|
+
override fun setZoom(view: ScannerView?, zoom: Double) {
|
|
132
140
|
view?.setZoom(zoom.toFloat())
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
@ReactProp(name = "pauseScanning")
|
|
136
|
-
fun setPauseScanning(view: ScannerView
|
|
137
|
-
if (
|
|
138
|
-
view
|
|
144
|
+
override fun setPauseScanning(view: ScannerView, value: Boolean) {
|
|
145
|
+
if (value) {
|
|
146
|
+
view.pauseScanning()
|
|
139
147
|
} else {
|
|
140
|
-
view
|
|
148
|
+
view.resumeScanning()
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
@ReactProp(name = "barcodeScanStrategy")
|
|
145
|
-
fun setBarcodeScanStrategy(view: ScannerView?, strategy: String?) {
|
|
153
|
+
override fun setBarcodeScanStrategy(view: ScannerView?, strategy: String?) {
|
|
146
154
|
view?.setBarcodeScanStrategy(strategy ?: "ALL")
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
@ReactProp(name = "keepScreenOn")
|
|
150
|
-
fun setKeepScreenOn(view: ScannerView
|
|
151
|
-
view
|
|
158
|
+
override fun setKeepScreenOn(view: ScannerView, value: Boolean) {
|
|
159
|
+
view.setKeepScreenOnEnabled(value)
|
|
152
160
|
}
|
|
153
161
|
|
|
154
162
|
@ReactProp(name = "barcodeEmissionInterval")
|
|
155
|
-
fun setBarcodeEmissionInterval(view: ScannerView?, interval: Double) {
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
override fun setBarcodeEmissionInterval(view: ScannerView?, interval: Double) {
|
|
164
|
+
Log.d("ScannerViewManager", "📊 [@ReactProp] barcodeEmissionInterval received: $interval")
|
|
165
|
+
|
|
166
|
+
// WithDefault<Double, 0.5> in TypeScript means codegen handles the default automatically
|
|
167
|
+
// If negative, clamp to 0 (minimum value)
|
|
168
|
+
// If 0, disable debouncing
|
|
169
|
+
// Otherwise, use the provided value (0 or positive)
|
|
170
|
+
val actualInterval = if (interval < 0) {
|
|
171
|
+
Log.d("ScannerViewManager", "📊 Clamping negative interval ($interval) to 0.0 (minimum)")
|
|
172
|
+
0.0 // Negative values clamped to 0 (minimum)
|
|
173
|
+
} else {
|
|
174
|
+
if (interval == 0.0) {
|
|
175
|
+
Log.d("ScannerViewManager", "📊 Using interval: ${interval}s (explicitly set to 0, will disable debouncing)")
|
|
176
|
+
} else {
|
|
177
|
+
Log.d("ScannerViewManager", "📊 Using interval: ${interval}s")
|
|
178
|
+
}
|
|
179
|
+
interval // Use provided value (0 or positive)
|
|
180
|
+
}
|
|
181
|
+
Log.d("ScannerViewManager", "📊 Final interval to set: ${actualInterval}s")
|
|
158
182
|
view?.setBarcodeEmissionInterval(actualInterval)
|
|
159
183
|
}
|
|
160
184
|
|
|
@@ -169,7 +193,16 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
|
|
|
169
193
|
"bubbled" to "onBarcodeScanned"
|
|
170
194
|
)
|
|
171
195
|
)
|
|
172
|
-
|
|
196
|
+
map["onLoad"] = mapOf(
|
|
197
|
+
"phasedRegistrationNames" to mapOf(
|
|
198
|
+
"bubbled" to "onLoad"
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
map["onScannerError"] = mapOf(
|
|
202
|
+
"phasedRegistrationNames" to mapOf(
|
|
203
|
+
"bubbled" to "onScannerError"
|
|
204
|
+
)
|
|
205
|
+
)
|
|
173
206
|
return map
|
|
174
207
|
}
|
|
175
208
|
}
|
package/ios/ScannerView.mm
CHANGED
|
@@ -263,7 +263,11 @@ using namespace facebook::react;
|
|
|
263
263
|
|
|
264
264
|
// Barcode emission interval
|
|
265
265
|
if (oldViewProps.barcodeEmissionInterval != newViewProps.barcodeEmissionInterval) {
|
|
266
|
-
|
|
266
|
+
// Handle negative values (clamp to 0)
|
|
267
|
+
double interval = newViewProps.barcodeEmissionInterval;
|
|
268
|
+
double actualInterval = interval < 0 ? 0.0 : interval;
|
|
269
|
+
|
|
270
|
+
NSNumber *intervalValue = @(actualInterval);
|
|
267
271
|
if ([_scannerImpl respondsToSelector:@selector(setBarcodeEmissionInterval:)]) {
|
|
268
272
|
[_scannerImpl performSelector:@selector(setBarcodeEmissionInterval:) withObject:intervalValue];
|
|
269
273
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import type {
|
|
7
7
|
DirectEventHandler,
|
|
8
8
|
Double,
|
|
9
|
+
WithDefault,
|
|
9
10
|
} from 'react-native/Libraries/Types/CodegenTypesNamespace';
|
|
10
11
|
|
|
11
12
|
// Define codegen types locally (no longer exported from react-native in 0.83)
|
|
@@ -111,7 +112,7 @@ export interface NativeProps extends ViewProps {
|
|
|
111
112
|
* Prevents rapid duplicate detections. Set to 0 to disable debouncing.
|
|
112
113
|
* @default 0.5
|
|
113
114
|
*/
|
|
114
|
-
barcodeEmissionInterval?: Double
|
|
115
|
+
barcodeEmissionInterval?: WithDefault<Double, 0.5>;
|
|
115
116
|
|
|
116
117
|
onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
|
|
117
118
|
onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ViewProps, type NativeSyntheticEvent } from 'react-native';
|
|
2
|
-
import type { DirectEventHandler, Double } from 'react-native/Libraries/Types/CodegenTypesNamespace';
|
|
2
|
+
import type { DirectEventHandler, Double, WithDefault } from 'react-native/Libraries/Types/CodegenTypesNamespace';
|
|
3
3
|
export interface BarcodeScannedEventPayload {
|
|
4
4
|
barcodes: {
|
|
5
5
|
data: string;
|
|
@@ -81,7 +81,7 @@ export interface NativeProps extends ViewProps {
|
|
|
81
81
|
* Prevents rapid duplicate detections. Set to 0 to disable debouncing.
|
|
82
82
|
* @default 0.5
|
|
83
83
|
*/
|
|
84
|
-
barcodeEmissionInterval?: Double
|
|
84
|
+
barcodeEmissionInterval?: WithDefault<Double, 0.5>;
|
|
85
85
|
onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
|
|
86
86
|
onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;
|
|
87
87
|
onLoad?: DirectEventHandler<OnLoadEventPayload>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScannerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/ScannerViewNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,kBAAkB,EAClB,MAAM,
|
|
1
|
+
{"version":3,"file":"ScannerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/ScannerViewNativeComponent.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleanuidev/react-native-scanner",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
4
|
-
"description": "scanner",
|
|
3
|
+
"version": "1.0.0-beta.3",
|
|
4
|
+
"description": "High-performance native barcode and QR code scanner for React Native. Scan barcodes in configurable target areas for precise detection. Built with CameraX & ML Kit (Android) and AVFoundation & Vision (iOS).",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -45,7 +45,31 @@
|
|
|
45
45
|
"keywords": [
|
|
46
46
|
"react-native",
|
|
47
47
|
"ios",
|
|
48
|
-
"android"
|
|
48
|
+
"android",
|
|
49
|
+
"barcode-scanner",
|
|
50
|
+
"qr-code-scanner",
|
|
51
|
+
"barcode",
|
|
52
|
+
"qr-code",
|
|
53
|
+
"qrcode",
|
|
54
|
+
"scanner",
|
|
55
|
+
"camera",
|
|
56
|
+
"camerax",
|
|
57
|
+
"ml-kit",
|
|
58
|
+
"avfoundation",
|
|
59
|
+
"vision",
|
|
60
|
+
"react-native-scanner",
|
|
61
|
+
"barcode-detection",
|
|
62
|
+
"qr-detection",
|
|
63
|
+
"mobile-scanner",
|
|
64
|
+
"native-scanner",
|
|
65
|
+
"fabric",
|
|
66
|
+
"new architecture",
|
|
67
|
+
"focus area",
|
|
68
|
+
"region scanning",
|
|
69
|
+
"frame scanning",
|
|
70
|
+
"area scanning",
|
|
71
|
+
"targeted-scanning",
|
|
72
|
+
"precise-scanning"
|
|
49
73
|
],
|
|
50
74
|
"repository": {
|
|
51
75
|
"type": "git",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import type {
|
|
7
7
|
DirectEventHandler,
|
|
8
8
|
Double,
|
|
9
|
+
WithDefault,
|
|
9
10
|
} from 'react-native/Libraries/Types/CodegenTypesNamespace';
|
|
10
11
|
|
|
11
12
|
// Define codegen types locally (no longer exported from react-native in 0.83)
|
|
@@ -111,7 +112,7 @@ export interface NativeProps extends ViewProps {
|
|
|
111
112
|
* Prevents rapid duplicate detections. Set to 0 to disable debouncing.
|
|
112
113
|
* @default 0.5
|
|
113
114
|
*/
|
|
114
|
-
barcodeEmissionInterval?: Double
|
|
115
|
+
barcodeEmissionInterval?: WithDefault<Double, 0.5>;
|
|
115
116
|
|
|
116
117
|
onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
|
|
117
118
|
onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;
|