@scr2em/capacitor-scanner 6.0.6 → 6.0.7
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 +27 -0
- package/android/src/main/java/com/leadliaion/capacitorscanner/CapacitorScannerPlugin.java +67 -2
- package/dist/docs.json +33 -0
- package/dist/esm/definitions.d.ts +5 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorScannerPlugin/CapacitorScannerPlugin.swift +85 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ npx cap sync
|
|
|
19
19
|
* [`capturePhoto()`](#capturephoto)
|
|
20
20
|
* [`checkPermissions()`](#checkpermissions)
|
|
21
21
|
* [`requestPermissions()`](#requestpermissions)
|
|
22
|
+
* [`flipCamera()`](#flipcamera)
|
|
23
|
+
* [`toggleFlash()`](#toggleflash)
|
|
22
24
|
* [`addListener('barcodeScanned', ...)`](#addlistenerbarcodescanned-)
|
|
23
25
|
* [`removeAllListeners()`](#removealllisteners)
|
|
24
26
|
* [Type Aliases](#type-aliases)
|
|
@@ -93,6 +95,26 @@ requestPermissions() => Promise<PermissionsResult>
|
|
|
93
95
|
--------------------
|
|
94
96
|
|
|
95
97
|
|
|
98
|
+
### flipCamera()
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
flipCamera() => Promise<void>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
--------------------
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### toggleFlash()
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
toggleFlash() => Promise<FlashResult>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Returns:** <code>Promise<<a href="#flashresult">FlashResult</a>></code>
|
|
114
|
+
|
|
115
|
+
--------------------
|
|
116
|
+
|
|
117
|
+
|
|
96
118
|
### addListener('barcodeScanned', ...)
|
|
97
119
|
|
|
98
120
|
```typescript
|
|
@@ -134,6 +156,11 @@ removeAllListeners() => Promise<void>
|
|
|
134
156
|
<code>{ camera: 'prompt' | 'denied' | 'granted' }</code>
|
|
135
157
|
|
|
136
158
|
|
|
159
|
+
#### FlashResult
|
|
160
|
+
|
|
161
|
+
<code>{ enabled: boolean }</code>
|
|
162
|
+
|
|
163
|
+
|
|
137
164
|
#### BarcodeScannedEvent
|
|
138
165
|
|
|
139
166
|
<code>{ scannedCode: string; format: string }</code>
|
|
@@ -2,6 +2,7 @@ package com.leadliaion.capacitorscanner;
|
|
|
2
2
|
|
|
3
3
|
import android.Manifest;
|
|
4
4
|
import android.content.Intent;
|
|
5
|
+
import android.content.pm.PackageManager;
|
|
5
6
|
import android.graphics.Color;
|
|
6
7
|
import android.net.Uri;
|
|
7
8
|
import android.provider.Settings;
|
|
@@ -17,6 +18,7 @@ import android.view.View;
|
|
|
17
18
|
import com.getcapacitor.JSArray;
|
|
18
19
|
|
|
19
20
|
import androidx.annotation.NonNull;
|
|
21
|
+
import androidx.camera.core.Camera;
|
|
20
22
|
import androidx.camera.core.CameraSelector;
|
|
21
23
|
|
|
22
24
|
import androidx.camera.core.ExperimentalGetImage;
|
|
@@ -79,6 +81,10 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
79
81
|
private ImageAnalysis imageAnalysis;
|
|
80
82
|
private ImageCapture imageCapture;
|
|
81
83
|
|
|
84
|
+
private boolean isFlashEnabled = false;
|
|
85
|
+
private int currentLensFacing = CameraSelector.LENS_FACING_BACK;
|
|
86
|
+
|
|
87
|
+
|
|
82
88
|
|
|
83
89
|
@Override
|
|
84
90
|
public void load() {
|
|
@@ -209,6 +215,9 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
209
215
|
});
|
|
210
216
|
}
|
|
211
217
|
|
|
218
|
+
private Camera camera;
|
|
219
|
+
|
|
220
|
+
|
|
212
221
|
private void bindCamera(@NonNull ProcessCameraProvider cameraProvider, PreviewView previewView, int lensFacing, PluginCall call) {
|
|
213
222
|
cameraProvider.unbindAll();
|
|
214
223
|
|
|
@@ -239,16 +248,17 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
239
248
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
|
240
249
|
.setTargetRotation(rotation)
|
|
241
250
|
.build();
|
|
242
|
-
|
|
243
251
|
imageAnalysis.setAnalyzer(executor, new BarcodeAnalyzer(call));
|
|
244
252
|
|
|
245
253
|
imageCapture = new ImageCapture.Builder()
|
|
246
254
|
.setTargetResolution(targetResolution)
|
|
247
255
|
.setTargetRotation(rotation)
|
|
256
|
+
.setFlashMode(isFlashEnabled ? ImageCapture.FLASH_MODE_ON : ImageCapture.FLASH_MODE_OFF)
|
|
248
257
|
.build();
|
|
249
258
|
|
|
250
259
|
try {
|
|
251
|
-
|
|
260
|
+
// Store the Camera instance for later use
|
|
261
|
+
camera = cameraProvider.bindToLifecycle(getActivity(), cameraSelector, preview, imageAnalysis, imageCapture);
|
|
252
262
|
preview.setSurfaceProvider(previewView.getSurfaceProvider());
|
|
253
263
|
} catch (Exception e) {
|
|
254
264
|
echo("Failed to bind camera to lifecycle: " + e.getMessage());
|
|
@@ -466,6 +476,61 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
466
476
|
}
|
|
467
477
|
}
|
|
468
478
|
|
|
479
|
+
|
|
480
|
+
@PluginMethod
|
|
481
|
+
public void flipCamera(PluginCall call) {
|
|
482
|
+
if (!isScanning.get()) {
|
|
483
|
+
call.reject("Camera is not running");
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
getActivity().runOnUiThread(() -> {
|
|
488
|
+
try {
|
|
489
|
+
currentLensFacing = (currentLensFacing == CameraSelector.LENS_FACING_BACK)
|
|
490
|
+
? CameraSelector.LENS_FACING_FRONT
|
|
491
|
+
: CameraSelector.LENS_FACING_BACK;
|
|
492
|
+
|
|
493
|
+
bindCamera(cameraProvider, previewView, currentLensFacing, call);
|
|
494
|
+
call.resolve();
|
|
495
|
+
} catch (Exception e) {
|
|
496
|
+
call.reject("Failed to flip camera: " + e.getMessage());
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
@PluginMethod
|
|
502
|
+
public void toggleFlash(PluginCall call) {
|
|
503
|
+
if (!isScanning.get()) {
|
|
504
|
+
call.reject("Camera is not running");
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
|
|
509
|
+
call.reject("Device doesn't have flash capability");
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
getActivity().runOnUiThread(() -> {
|
|
514
|
+
try {
|
|
515
|
+
if (camera != null) {
|
|
516
|
+
// Toggle the flash state
|
|
517
|
+
isFlashEnabled = !isFlashEnabled;
|
|
518
|
+
camera.getCameraControl().enableTorch(isFlashEnabled);
|
|
519
|
+
|
|
520
|
+
JSObject ret = new JSObject();
|
|
521
|
+
ret.put("enabled", isFlashEnabled);
|
|
522
|
+
call.resolve(ret);
|
|
523
|
+
} else {
|
|
524
|
+
call.reject("Camera is not initialized");
|
|
525
|
+
}
|
|
526
|
+
} catch (Exception e) {
|
|
527
|
+
call.reject("Failed to toggle flash: " + e.getMessage());
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
469
534
|
private void logLongMessage(String message) {
|
|
470
535
|
if (message.length() > 4000) {
|
|
471
536
|
int chunkCount = message.length() / 4000;
|
package/dist/docs.json
CHANGED
|
@@ -79,6 +79,28 @@
|
|
|
79
79
|
],
|
|
80
80
|
"slug": "requestpermissions"
|
|
81
81
|
},
|
|
82
|
+
{
|
|
83
|
+
"name": "flipCamera",
|
|
84
|
+
"signature": "() => Promise<void>",
|
|
85
|
+
"parameters": [],
|
|
86
|
+
"returns": "Promise<void>",
|
|
87
|
+
"tags": [],
|
|
88
|
+
"docs": "",
|
|
89
|
+
"complexTypes": [],
|
|
90
|
+
"slug": "flipcamera"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "toggleFlash",
|
|
94
|
+
"signature": "() => Promise<FlashResult>",
|
|
95
|
+
"parameters": [],
|
|
96
|
+
"returns": "Promise<FlashResult>",
|
|
97
|
+
"tags": [],
|
|
98
|
+
"docs": "",
|
|
99
|
+
"complexTypes": [
|
|
100
|
+
"FlashResult"
|
|
101
|
+
],
|
|
102
|
+
"slug": "toggleflash"
|
|
103
|
+
},
|
|
82
104
|
{
|
|
83
105
|
"name": "addListener",
|
|
84
106
|
"signature": "(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void) => Promise<void>",
|
|
@@ -226,6 +248,17 @@
|
|
|
226
248
|
}
|
|
227
249
|
]
|
|
228
250
|
},
|
|
251
|
+
{
|
|
252
|
+
"name": "FlashResult",
|
|
253
|
+
"slug": "flashresult",
|
|
254
|
+
"docs": "",
|
|
255
|
+
"types": [
|
|
256
|
+
{
|
|
257
|
+
"text": "{ enabled: boolean }",
|
|
258
|
+
"complexTypes": []
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
},
|
|
229
262
|
{
|
|
230
263
|
"name": "BarcodeScannedEvent",
|
|
231
264
|
"slug": "barcodescannedevent",
|
|
@@ -5,6 +5,8 @@ export interface CapacitorScannerPlugin {
|
|
|
5
5
|
capturePhoto(): Promise<CapturePhotoResult>;
|
|
6
6
|
checkPermissions(): Promise<PermissionsResult>;
|
|
7
7
|
requestPermissions(): Promise<PermissionsResult>;
|
|
8
|
+
flipCamera(): Promise<void>;
|
|
9
|
+
toggleFlash(): Promise<FlashResult>;
|
|
8
10
|
addListener(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void): Promise<void>;
|
|
9
11
|
removeAllListeners(): Promise<void>;
|
|
10
12
|
}
|
|
@@ -23,6 +25,9 @@ export declare type PermissionsResult = {
|
|
|
23
25
|
export declare type CapturePhotoResult = {
|
|
24
26
|
imageBase64: string;
|
|
25
27
|
};
|
|
28
|
+
export declare type FlashResult = {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
};
|
|
26
31
|
export declare enum BarcodeFormat {
|
|
27
32
|
Aztec = "AZTEC",
|
|
28
33
|
Code39 = "CODE_39",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAN,IAAY,aAYX;AAZD,WAAY,aAAa;IACvB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,qCAAoB,CAAA;IACpB,2CAA0B,CAAA;IAC1B,+BAAc,CAAA;IACd,iCAAgB,CAAA;IAChB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,+BAAc,CAAA;AAChB,CAAC,EAZW,aAAa,KAAb,aAAa,QAYxB","sourcesContent":["export interface CapacitorScannerPlugin {\n startScanning(options?: ScannerOptions): Promise<void>;\n stopScanning(): Promise<void>;\n openSettings(): Promise<void>;\n capturePhoto(): Promise<CapturePhotoResult>;\n checkPermissions(): Promise<PermissionsResult>;\n requestPermissions(): Promise<PermissionsResult>;\n flipCamera(): Promise<void>;\n toggleFlash(): Promise<FlashResult>;\n addListener(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void): Promise<void>;\n removeAllListeners(): Promise<void>;\n}\n\nexport type ScannerOptions = {\n formats?: BarcodeFormat[];\n cameraDirection?: 'BACK' | 'FRONT';\n debounceTimeInMilli?: number\n};\n\nexport type BarcodeScannedEvent = { scannedCode: string; format: string };\n\nexport type PermissionsResult = { camera: 'prompt' | 'denied' | 'granted' };\n\nexport type CapturePhotoResult = { imageBase64: string };\n\nexport type FlashResult = { enabled: boolean };\n\nexport enum BarcodeFormat {\n Aztec = 'AZTEC',\n Code39 = 'CODE_39',\n Code93 = 'CODE_93',\n Code128 = 'CODE_128',\n DataMatrix = 'DATA_MATRIX',\n Ean8 = 'EAN_8',\n Ean13 = 'EAN_13',\n Itf14 = 'ITF14',\n Pdf417 = 'PDF_417',\n QrCode = 'QR_CODE',\n UpcE = 'UPC_E',\n}\n\ndeclare global {\n interface PluginRegistry {\n QRScanner: CapacitorScannerPlugin;\n }\n}"]}
|
|
@@ -23,6 +23,8 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
|
|
|
23
23
|
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
|
|
24
24
|
CAPPluginMethod(name: "openSettings", returnType: CAPPluginReturnPromise),
|
|
25
25
|
CAPPluginMethod(name: "capturePhoto", returnType: CAPPluginReturnPromise),
|
|
26
|
+
CAPPluginMethod(name: "flipCamera", returnType: CAPPluginReturnPromise),
|
|
27
|
+
CAPPluginMethod(name: "toggleFlash", returnType: CAPPluginReturnPromise),
|
|
26
28
|
]
|
|
27
29
|
|
|
28
30
|
private var captureSession: AVCaptureSession?
|
|
@@ -376,6 +378,89 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
|
|
|
376
378
|
self.scannedCodesVotes[payload] = voteStatus
|
|
377
379
|
}
|
|
378
380
|
}
|
|
381
|
+
|
|
382
|
+
@objc func flipCamera(_ call: CAPPluginCall) {
|
|
383
|
+
guard let session = self.captureSession else {
|
|
384
|
+
call.reject("Scanning session not active.")
|
|
385
|
+
return
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
389
|
+
session.beginConfiguration()
|
|
390
|
+
// Defer ensures commitConfiguration is called even if errors occur
|
|
391
|
+
defer { session.commitConfiguration() }
|
|
392
|
+
|
|
393
|
+
guard let currentInput = session.inputs.first as? AVCaptureDeviceInput else {
|
|
394
|
+
call.reject("Could not get current camera input.")
|
|
395
|
+
return
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
let currentPosition = currentInput.device.position
|
|
399
|
+
let preferredPosition: AVCaptureDevice.Position = (currentPosition == .back) ? .front : .back
|
|
400
|
+
|
|
401
|
+
guard let newDevice = self.getCaptureDevice(position: preferredPosition) else {
|
|
402
|
+
call.reject("Could not find camera for position: \(preferredPosition).")
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
guard let newInput = try? AVCaptureDeviceInput(device: newDevice) else {
|
|
407
|
+
call.reject("Could not create input for new camera device.")
|
|
408
|
+
return
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Remove the existing input
|
|
412
|
+
session.removeInput(currentInput)
|
|
413
|
+
|
|
414
|
+
// Add the new input
|
|
415
|
+
if session.canAddInput(newInput) {
|
|
416
|
+
session.addInput(newInput)
|
|
417
|
+
|
|
418
|
+
// Session automatically handles connecting outputs (like photoOutput and videoDataOutput)
|
|
419
|
+
// to the new input. No explicit reconnection needed here.
|
|
420
|
+
|
|
421
|
+
// Ensure preview layer orientation is updated for the new camera
|
|
422
|
+
DispatchQueue.main.async {
|
|
423
|
+
self.updatePreviewOrientation()
|
|
424
|
+
call.resolve() // Resolve the call on the main thread after UI update
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
} else {
|
|
428
|
+
// Important: If adding the new input fails, try to add the old one back!
|
|
429
|
+
print("Failed to add new input, attempting to restore previous input.")
|
|
430
|
+
if session.canAddInput(currentInput) {
|
|
431
|
+
session.addInput(currentInput)
|
|
432
|
+
}
|
|
433
|
+
call.reject("Could not add new camera input to session.")
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
@objc func toggleFlash(_ call: CAPPluginCall) {
|
|
439
|
+
guard let session = self.captureSession, let currentInput = session.inputs.first as? AVCaptureDeviceInput else {
|
|
440
|
+
call.reject("Scanning session not active or camera input not found.")
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
let device = currentInput.device
|
|
445
|
+
|
|
446
|
+
guard device.hasTorch, device.isTorchAvailable else {
|
|
447
|
+
call.resolve(["enabled": false]) // Report flash as disabled if not available/supported
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
do {
|
|
452
|
+
try device.lockForConfiguration()
|
|
453
|
+
let currentMode = device.torchMode
|
|
454
|
+
let newMode: AVCaptureDevice.TorchMode = (currentMode == .on) ? .off : .on
|
|
455
|
+
if device.isTorchModeSupported(newMode) {
|
|
456
|
+
device.torchMode = newMode
|
|
457
|
+
}
|
|
458
|
+
device.unlockForConfiguration()
|
|
459
|
+
call.resolve(["enabled": device.torchMode == .on])
|
|
460
|
+
} catch {
|
|
461
|
+
call.reject("Could not lock device for flash configuration: \(error.localizedDescription)")
|
|
462
|
+
}
|
|
463
|
+
}
|
|
379
464
|
}
|
|
380
465
|
|
|
381
466
|
extension CapacitorScannerPlugin: AVCaptureVideoDataOutputSampleBufferDelegate {
|