capacitor-camera-view 2.4.0 → 3.0.1

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 (44) hide show
  1. package/CapacitorCameraView.podspec +1 -1
  2. package/Package.swift +1 -1
  3. package/README.md +341 -49
  4. package/android/build.gradle +0 -1
  5. package/android/src/main/AndroidManifest.xml +0 -1
  6. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraError.kt +42 -0
  7. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraView.kt +945 -207
  8. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraViewPlugin.kt +87 -43
  9. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/BarcodeDetectionResult.kt +28 -2
  10. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraDevice.kt +6 -1
  11. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraSessionConfiguration.kt +15 -1
  12. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/TorchModeState.kt +15 -0
  13. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/WebBoundingRect.kt +1 -1
  14. package/android/src/main/java/com/michaelwolz/capacitorcameraview/utils.kt +73 -19
  15. package/dist/docs.json +475 -30
  16. package/dist/esm/definitions.d.ts +478 -26
  17. package/dist/esm/definitions.js.map +1 -1
  18. package/dist/esm/utils.d.ts +59 -15
  19. package/dist/esm/utils.js +79 -38
  20. package/dist/esm/utils.js.map +1 -1
  21. package/dist/esm/web.d.ts +191 -13
  22. package/dist/esm/web.js +624 -141
  23. package/dist/esm/web.js.map +1 -1
  24. package/dist/plugin.cjs.js +711 -179
  25. package/dist/plugin.cjs.js.map +1 -1
  26. package/dist/plugin.js +711 -179
  27. package/dist/plugin.js.map +1 -1
  28. package/ios/Sources/CameraViewPlugin/CameraError.swift +147 -2
  29. package/ios/Sources/CameraViewPlugin/CameraEvents.swift +41 -19
  30. package/ios/Sources/CameraViewPlugin/CameraSessionConfiguration.swift +29 -1
  31. package/ios/Sources/CameraViewPlugin/CameraViewManager+BarcodeScan.swift +78 -23
  32. package/ios/Sources/CameraViewPlugin/CameraViewManager+DeferredStart.swift +37 -0
  33. package/ios/Sources/CameraViewPlugin/CameraViewManager+Focus.swift +131 -0
  34. package/ios/Sources/CameraViewPlugin/CameraViewManager+Lifecycle.swift +156 -0
  35. package/ios/Sources/CameraViewPlugin/CameraViewManager+PhotoCapture.swift +73 -41
  36. package/ios/Sources/CameraViewPlugin/CameraViewManager+ResolutionSelection.swift +57 -0
  37. package/ios/Sources/CameraViewPlugin/CameraViewManager+Rotation.swift +200 -0
  38. package/ios/Sources/CameraViewPlugin/CameraViewManager+VideoDataOutput.swift +24 -12
  39. package/ios/Sources/CameraViewPlugin/CameraViewManager+VideoRecording.swift +22 -73
  40. package/ios/Sources/CameraViewPlugin/CameraViewManager+Zoom.swift +113 -0
  41. package/ios/Sources/CameraViewPlugin/CameraViewManager.swift +450 -403
  42. package/ios/Sources/CameraViewPlugin/CameraViewPlugin.swift +98 -65
  43. package/ios/Sources/CameraViewPlugin/Utils.swift +61 -7
  44. package/package.json +25 -9
@@ -35,6 +35,7 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
35
35
  CAPPluginMethod(name: "flipCamera", returnType: CAPPluginReturnPromise),
36
36
  CAPPluginMethod(name: "getZoom", returnType: CAPPluginReturnPromise),
37
37
  CAPPluginMethod(name: "setZoom", returnType: CAPPluginReturnPromise),
38
+ CAPPluginMethod(name: "setFocusPoint", returnType: CAPPluginReturnPromise),
38
39
  CAPPluginMethod(name: "getFlashMode", returnType: CAPPluginReturnPromise),
39
40
  CAPPluginMethod(name: "getSupportedFlashModes", returnType: CAPPluginReturnPromise),
40
41
  CAPPluginMethod(name: "setFlashMode", returnType: CAPPluginReturnPromise),
@@ -54,25 +55,41 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
54
55
  public func cameraDidDetectBarcode(_ event: BarcodeDetectedEvent) {
55
56
  notifyListeners("barcodeDetected", data: event.toDictionary())
56
57
  }
58
+
59
+ public func cameraWasInterrupted(reason: String) {
60
+ notifyListeners("cameraInterrupted", data: ["reason": reason])
61
+ }
62
+
63
+ public func cameraInterruptionEnded() {
64
+ notifyListeners("cameraResumed", data: [:])
65
+ }
66
+
67
+ public func cameraRuntimeError(message: String, code: Int?) {
68
+ var data: [String: Any] = ["message": message]
69
+ if let code = code {
70
+ data["code"] = code
71
+ }
72
+ notifyListeners("cameraRuntimeError", data: data)
73
+ }
57
74
 
58
75
  @objc func start(_ call: CAPPluginCall) {
59
76
  guard let webView = self.webView else {
60
- call.reject("Cannot find web view")
77
+ call.reject("Cannot find web view", CameraError.missingWebView.code)
61
78
  return
62
79
  }
63
-
80
+
64
81
  maybeRequestCameraAccess { [weak self] granted in
65
82
  guard granted else {
66
- call.reject("Camera access denied")
83
+ call.reject("Camera access denied", CameraError.permissionDenied.code)
67
84
  return
68
85
  }
69
-
86
+
70
87
  self?.implementation.startSession(
71
88
  configuration: sessionConfigFromPluginCall(call),
72
89
  webView: webView,
73
90
  completion: { (error) in
74
91
  if let error = error {
75
- call.reject("Failed to start camera preview", nil, error)
92
+ call.reject("Failed to start camera preview", error.cameraErrorCode, error)
76
93
  return
77
94
  }
78
95
  call.resolve()
@@ -97,22 +114,22 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
97
114
  let saveToFile = call.getBool("saveToFile", false)
98
115
 
99
116
  guard quality >= 0.0 && quality <= 100.0 else {
100
- call.reject("Quality must be between 0 and 100")
117
+ call.reject("Quality must be between 0 and 100", CameraError.invalidArgument.code)
101
118
  return
102
119
  }
103
-
120
+
104
121
  // Use optimized Data-based capture to avoid double JPEG encoding
105
122
  implementation.capturePhotoData(completion: { [weak self] (data, error) in
106
123
  if let error = error {
107
- call.reject("Failed to capture image", nil, error)
124
+ call.reject("Failed to capture image", error.cameraErrorCode, error)
108
125
  return
109
126
  }
110
-
127
+
111
128
  guard let originalData = data else {
112
- call.reject("No image data")
129
+ call.reject("No image data", CameraError.captureOutputMissing.code)
113
130
  return
114
131
  }
115
-
132
+
116
133
  // Determine final image data based on quality setting
117
134
  // For quality >= 90%, use original camera JPEG data to avoid re-encoding
118
135
  // For lower quality, re-encode to reduce file size
@@ -121,33 +138,34 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
121
138
  // Use original JPEG data from camera (avoids quality loss and CPU overhead)
122
139
  imageData = originalData
123
140
  } else {
124
- // Re-encode at lower quality for smaller file size
125
- guard let image = UIImage(data: originalData),
126
- let compressedData = image.jpegData(compressionQuality: quality / 100.0) else {
127
- call.reject("Failed to compress image")
141
+ // Re-encode at lower quality for smaller file size. Uses ImageIO
142
+ // directly (rather than UIImage.jpegData) so EXIF/GPS metadata
143
+ // from the original camera JPEG survives the re-encode.
144
+ guard let compressedData = reencodeJPEG(data: originalData, compressionQuality: quality / 100.0) else {
145
+ call.reject("Failed to compress image", CameraError.imageCompressionFailed.code)
128
146
  return
129
147
  }
130
148
  imageData = compressedData
131
149
  }
132
-
150
+
133
151
  if saveToFile {
134
152
  // Use TempFileManager for tracked temp files with automatic cleanup
135
153
  let tempFileURL = TempFileManager.shared.createTempImageFile()
136
154
  do {
137
155
  try imageData.write(to: tempFileURL)
138
-
156
+
139
157
  // Convert file URL to webView-accessible path using Capacitor bridge
140
158
  guard let webPath = self?.bridge?.portablePath(fromLocalURL: tempFileURL)?.absoluteString else {
141
- call.reject("Failed to create web-accessible path")
159
+ call.reject("Failed to create web-accessible path", CameraError.pathConversionFailed.code)
142
160
  return
143
161
  }
144
-
162
+
145
163
  call.resolve([
146
164
  "path": tempFileURL.absoluteString,
147
165
  "webPath": webPath,
148
166
  ])
149
167
  } catch {
150
- call.reject("Failed to save image to file", nil, error)
168
+ call.reject("Failed to save image to file", CameraError.fileWriteFailed.code, error)
151
169
  }
152
170
  } else {
153
171
  // Return as base64
@@ -163,44 +181,44 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
163
181
  let saveToFile = call.getBool("saveToFile", false)
164
182
 
165
183
  guard quality >= 0.0 && quality <= 100.0 else {
166
- call.reject("Quality must be between 0 and 100")
184
+ call.reject("Quality must be between 0 and 100", CameraError.invalidArgument.code)
167
185
  return
168
186
  }
169
-
187
+
170
188
  implementation.captureSnapshot { [weak self] (image, error) in
171
189
  if let error = error {
172
- call.reject("Failed to capture frame", nil, error)
190
+ call.reject("Failed to capture frame", error.cameraErrorCode, error)
173
191
  return
174
192
  }
175
-
193
+
176
194
  guard let image = image else {
177
- call.reject("No frame data")
195
+ call.reject("No frame data", CameraError.captureOutputMissing.code)
178
196
  return
179
197
  }
180
-
198
+
181
199
  guard let imageData = image.jpegData(compressionQuality: quality / 100.0) else {
182
- call.reject("Failed to compress image")
200
+ call.reject("Failed to compress image", CameraError.imageCompressionFailed.code)
183
201
  return
184
202
  }
185
-
203
+
186
204
  if saveToFile {
187
205
  // Use TempFileManager for tracked temp files with automatic cleanup
188
206
  let tempFileURL = TempFileManager.shared.createTempImageFile()
189
207
  do {
190
208
  try imageData.write(to: tempFileURL)
191
-
209
+
192
210
  // Convert file URL to webView-accessible path using Capacitor bridge
193
211
  guard let webPath = self?.bridge?.portablePath(fromLocalURL: tempFileURL)?.absoluteString else {
194
- call.reject("Failed to create web-accessible path")
212
+ call.reject("Failed to create web-accessible path", CameraError.pathConversionFailed.code)
195
213
  return
196
214
  }
197
-
215
+
198
216
  call.resolve([
199
217
  "path": tempFileURL.absoluteString,
200
218
  "webPath": webPath,
201
219
  ])
202
220
  } catch {
203
- call.reject("Failed to save sample to file", nil, error)
221
+ call.reject("Failed to save sample to file", CameraError.fileWriteFailed.code, error)
204
222
  }
205
223
  } else {
206
224
  // Return as base64
@@ -216,14 +234,14 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
216
234
  let videoQuality = call.getString("videoQuality") ?? "highest"
217
235
 
218
236
  guard let parsedVideoQuality = VideoRecordingQuality(rawValue: videoQuality) else {
219
- call.reject("Invalid videoQuality. Use one of: lowest, sd, hd, fhd, uhd, highest")
237
+ call.reject("Invalid videoQuality. Use one of: lowest, sd, hd, fhd, uhd, highest", CameraError.invalidArgument.code)
220
238
  return
221
239
  }
222
-
240
+
223
241
  if enableAudio {
224
242
  maybeRequestMicrophoneAccess { [weak self] granted in
225
243
  guard granted else {
226
- call.reject("Microphone access denied")
244
+ call.reject("Microphone access denied", CameraError.permissionDenied.code)
227
245
  return
228
246
  }
229
247
  self?.doStartRecording(call: call, enableAudio: true, videoQuality: parsedVideoQuality)
@@ -232,7 +250,7 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
232
250
  doStartRecording(call: call, enableAudio: false, videoQuality: parsedVideoQuality)
233
251
  }
234
252
  }
235
-
253
+
236
254
  private func doStartRecording(
237
255
  call: CAPPluginCall,
238
256
  enableAudio: Bool,
@@ -240,30 +258,30 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
240
258
  ) {
241
259
  implementation.startRecording(enableAudio: enableAudio, videoQuality: videoQuality) { error in
242
260
  if let error = error {
243
- call.reject("Failed to start recording", nil, error)
261
+ call.reject("Failed to start recording", error.cameraErrorCode, error)
244
262
  return
245
263
  }
246
264
  call.resolve()
247
265
  }
248
266
  }
249
-
267
+
250
268
  @objc func stopRecording(_ call: CAPPluginCall) {
251
269
  implementation.stopRecording { [weak self] (outputURL, error) in
252
270
  if let error = error {
253
- call.reject("Failed to stop recording", nil, error)
271
+ call.reject("Failed to stop recording", error.cameraErrorCode, error)
254
272
  return
255
273
  }
256
-
274
+
257
275
  guard let outputURL = outputURL else {
258
- call.reject("No output file URL")
276
+ call.reject("No output file URL", CameraError.captureOutputMissing.code)
259
277
  return
260
278
  }
261
-
279
+
262
280
  guard let webPath = self?.bridge?.portablePath(fromLocalURL: outputURL)?.absoluteString else {
263
- call.reject("Failed to create web-accessible path")
281
+ call.reject("Failed to create web-accessible path", CameraError.pathConversionFailed.code)
264
282
  return
265
283
  }
266
-
284
+
267
285
  call.resolve([
268
286
  "path": outputURL.absoluteString,
269
287
  "webPath": webPath,
@@ -290,12 +308,12 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
290
308
  }
291
309
 
292
310
  @objc func flipCamera(_ call: CAPPluginCall) {
293
- do {
294
- try implementation.flipCamera()
311
+ implementation.flipCamera { error in
312
+ if let error = error {
313
+ call.reject("Failed to switch camera", error.cameraErrorCode, error)
314
+ return
315
+ }
295
316
  call.resolve()
296
- } catch {
297
- call.reject("Failed to switch camera", nil, error)
298
- return
299
317
  }
300
318
  }
301
319
 
@@ -311,21 +329,36 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
311
329
 
312
330
  @objc func setZoom(_ call: CAPPluginCall) {
313
331
  guard let level = call.getDouble("level") else {
314
- call.reject("Zoom level must be provided")
332
+ call.reject("Zoom level must be provided", CameraError.invalidArgument.code)
315
333
  return
316
334
  }
317
-
335
+
318
336
  let ramp = call.getBool("ramp") ?? false
319
-
337
+
320
338
  do {
321
339
  try implementation.setZoomFactor(level, ramp: ramp)
322
340
  call.resolve()
323
341
  } catch {
324
- call.reject("Failed to set zoom level", nil, error)
342
+ call.reject("Failed to set zoom level", error.cameraErrorCode, error)
325
343
  return
326
344
  }
327
345
  }
328
346
 
347
+ @objc func setFocusPoint(_ call: CAPPluginCall) {
348
+ guard let pointX = call.getDouble("x"), let pointY = call.getDouble("y") else {
349
+ call.reject("Focus point x and y must be provided", CameraError.invalidArgument.code)
350
+ return
351
+ }
352
+
353
+ implementation.setFocusPoint(x: CGFloat(pointX), y: CGFloat(pointY)) { error in
354
+ if let error = error {
355
+ call.reject("Failed to set focus point", error.cameraErrorCode, error)
356
+ return
357
+ }
358
+ call.resolve()
359
+ }
360
+ }
361
+
329
362
  @objc func getFlashMode(_ call: CAPPluginCall) {
330
363
  let flashMode = implementation.getFlashMode()
331
364
 
@@ -336,7 +369,7 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
336
369
 
337
370
  @objc func getSupportedFlashModes(_ call: CAPPluginCall) {
338
371
  let supportedFlashModes = implementation.getSupportedFlashModes()
339
- let supportedFlashModeStrArr = supportedFlashModes.map { flashModeToStrMap[$0] }
372
+ let supportedFlashModeStrArr = supportedFlashModes.compactMap { flashModeToStrMap[$0] }
340
373
 
341
374
  call.resolve([
342
375
  "flashModes": supportedFlashModeStrArr
@@ -345,20 +378,20 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
345
378
 
346
379
  @objc func setFlashMode(_ call: CAPPluginCall) {
347
380
  guard let mode = call.getString("mode") else {
348
- call.reject("Flash mode must be provided")
381
+ call.reject("Flash mode must be provided", CameraError.invalidArgument.code)
349
382
  return
350
383
  }
351
-
384
+
352
385
  guard let flashMode = strToFlashModeMap[mode] else {
353
- call.reject("Invalid flash mode")
386
+ call.reject("Invalid flash mode", CameraError.invalidArgument.code)
354
387
  return
355
388
  }
356
-
389
+
357
390
  do {
358
391
  try implementation.setFlashMode(flashMode)
359
392
  call.resolve()
360
393
  } catch {
361
- call.reject("Failed to set flash mode", nil, error)
394
+ call.reject("Failed to set flash mode", error.cameraErrorCode, error)
362
395
  }
363
396
  }
364
397
 
@@ -379,22 +412,22 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin, CameraEventDelegate
379
412
 
380
413
  @objc func setTorchMode(_ call: CAPPluginCall) {
381
414
  guard let enabled = call.getBool("enabled") else {
382
- call.reject("Enabled parameter is required")
415
+ call.reject("Enabled parameter is required", CameraError.invalidArgument.code)
383
416
  return
384
417
  }
385
-
418
+
386
419
  let level = call.getFloat("level") ?? 1.0
387
-
420
+
388
421
  guard level >= 0.0 && level <= 1.0 else {
389
- call.reject("Level must be between 0.0 and 1.0")
422
+ call.reject("Level must be between 0.0 and 1.0", CameraError.invalidArgument.code)
390
423
  return
391
424
  }
392
-
425
+
393
426
  do {
394
427
  try implementation.setTorchMode(enabled: enabled, level: level)
395
428
  call.resolve()
396
429
  } catch {
397
- call.reject("Failed to set torch mode", nil, error)
430
+ call.reject("Failed to set torch mode", error.cameraErrorCode, error)
398
431
  }
399
432
  }
400
433
 
@@ -1,4 +1,11 @@
1
1
  import AVFoundation
2
+ import ImageIO
3
+ import os
4
+ import UniformTypeIdentifiers
5
+
6
+ /// Shared logger for camera plugin diagnostics (visible in Console.app / `log stream`),
7
+ /// used instead of `print()` so failures are visible in production logs.
8
+ internal let cameraViewLogger = Logger(subsystem: "com.michaelwolz.capacitorcameraview", category: "CameraViewManager")
2
9
 
3
10
  // MARK: - Camera Type Conversion
4
11
 
@@ -57,25 +64,66 @@ public func convertToNativeCameraTypes(_ stringTypes: [String]) -> [AVCaptureDev
57
64
  return stringTypes.compactMap { convertToNativeCameraType($0) }
58
65
  }
59
66
 
60
- /// Creates a temporary file URL for storing captured images
61
- /// @deprecated Use TempFileManager.shared.createTempImageFile() for automatic cleanup
62
- public func createTempImageFile() throws -> URL {
63
- let timestamp = Int(Date().timeIntervalSince1970 * 1000)
64
- let fileName = "camera_capture_\(timestamp).jpg"
65
- let tempDir = FileManager.default.temporaryDirectory
66
- return tempDir.appendingPathComponent(fileName)
67
+ // MARK: - Image Re-encoding
68
+
69
+ /// Re-encodes JPEG data at a lower compression quality while preserving the
70
+ /// original image metadata (EXIF, TIFF, GPS, orientation, etc.).
71
+ ///
72
+ /// Uses ImageIO directly instead of round-tripping through `UIImage`/
73
+ /// `UIImage.jpegData(compressionQuality:)`, which silently drops all metadata
74
+ /// from the source JPEG.
75
+ ///
76
+ /// - Parameters:
77
+ /// - data: The source JPEG data.
78
+ /// - compressionQuality: The lossy compression quality (0.0-1.0).
79
+ /// - Returns: The re-encoded JPEG data, or nil if the source data or
80
+ /// destination could not be created.
81
+ public func reencodeJPEG(data: Data, compressionQuality: CGFloat) -> Data? {
82
+ guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
83
+ return nil
84
+ }
85
+
86
+ let destinationData = NSMutableData()
87
+ guard let destination = CGImageDestinationCreateWithData(
88
+ destinationData,
89
+ UTType.jpeg.identifier as CFString,
90
+ 1,
91
+ nil
92
+ ) else {
93
+ return nil
94
+ }
95
+
96
+ // Start from the source image's own metadata so EXIF/GPS/orientation
97
+ // survive the re-encode, then layer the compression quality on top.
98
+ var properties = (CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any]) ?? [:]
99
+ properties[kCGImageDestinationLossyCompressionQuality] = compressionQuality
100
+
101
+ CGImageDestinationAddImageFromSource(destination, source, 0, properties as CFDictionary)
102
+
103
+ guard CGImageDestinationFinalize(destination) else {
104
+ return nil
105
+ }
106
+
107
+ return destinationData as Data
67
108
  }
68
109
 
69
110
  // MARK: - Barcode Type Conversion
70
111
 
71
112
  /// All supported barcode types for detection.
72
113
  /// These are enabled by default when no specific types are configured.
114
+ ///
115
+ /// Note: there is no UPC-A entry. AVFoundation has no UPC-A metadata object
116
+ /// type and reports UPC-A codes as `.ean13` (a UPC-A value is an EAN-13 with a
117
+ /// leading `0`), so on iOS the `upcA` union member is neither requestable nor
118
+ /// emitted — such codes arrive as `ean13`. `.codabar` is available since iOS
119
+ /// 15.4; the deployment target is 16, so no availability guard is needed.
73
120
  public let ALL_SUPPORTED_BARCODE_TYPES: [AVMetadataObject.ObjectType] = [
74
121
  .qr,
75
122
  .code128,
76
123
  .code39,
77
124
  .code39Mod43,
78
125
  .code93,
126
+ .codabar,
79
127
  .ean8,
80
128
  .ean13,
81
129
  .interleaved2of5,
@@ -101,6 +149,10 @@ public func convertToNativeBarcodeType(_ stringType: String) -> AVMetadataObject
101
149
  return .code39Mod43
102
150
  case "code93":
103
151
  return .code93
152
+ case "codabar":
153
+ return .codabar
154
+ // Note: "upcA" is intentionally unmapped. AVFoundation has no UPC-A metadata
155
+ // type and reports UPC-A codes as .ean13, so it cannot be requested on iOS.
104
156
  case "ean8":
105
157
  return .ean8
106
158
  case "ean13":
@@ -137,6 +189,8 @@ public func convertToStringBarcodeType(_ barcodeType: AVMetadataObject.ObjectTyp
137
189
  return "code39Mod43"
138
190
  case .code93:
139
191
  return "code93"
192
+ case .codabar:
193
+ return "codabar"
140
194
  case .ean8:
141
195
  return "ean8"
142
196
  case .ean13:
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "capacitor-camera-view",
3
- "version": "2.4.0",
3
+ "version": "3.0.1",
4
4
  "description": "A Capacitor plugin for embedding a live camera feed directly into your app.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
7
7
  "types": "dist/esm/index.d.ts",
8
8
  "unpkg": "dist/plugin.js",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/esm/index.d.ts",
12
+ "import": "./dist/esm/index.js",
13
+ "require": "./dist/plugin.cjs.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "sideEffects": false,
9
18
  "files": [
10
19
  "android/src/main/",
11
20
  "android/build.gradle",
@@ -29,23 +38,29 @@
29
38
  "plugin",
30
39
  "native"
31
40
  ],
41
+ "packageManager": "pnpm@11.18.0",
42
+ "engines": {
43
+ "node": ">=24",
44
+ "pnpm": ">=11"
45
+ },
32
46
  "scripts": {
33
- "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
47
+ "verify": "pnpm run verify:ios && pnpm run verify:android && pnpm run verify:web",
34
48
  "verify:ios": "xcodebuild -scheme CapacitorCameraView -destination generic/platform=iOS",
35
49
  "verify:android": "cd android && ./gradlew clean build test && cd ..",
36
- "verify:web": "npm run build",
37
- "lint": "npm run eslint",
38
- "lint:ios": "npm run swiftlint -- lint",
39
- "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
50
+ "verify:web": "pnpm run build",
51
+ "lint": "pnpm run eslint",
52
+ "lint:ios": "pnpm run swiftlint lint",
53
+ "fmt": "pnpm run eslint --fix && pnpm run prettier --write && pnpm run swiftlint --fix --format",
40
54
  "eslint": "eslint . --ext ts",
41
55
  "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
42
56
  "prettier:check": "prettier --check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
43
57
  "swiftlint": "node-swiftlint",
58
+ "test": "vitest run",
44
59
  "docgen": "docgen --api CameraViewPlugin --output-readme README.md --output-json dist/docs.json",
45
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
60
+ "build": "pnpm run clean && pnpm run docgen && tsc && rollup -c rollup.config.mjs",
46
61
  "clean": "rimraf ./dist",
47
62
  "watch": "tsc --watch",
48
- "prepublishOnly": "npm run build"
63
+ "prepublishOnly": "pnpm run build"
49
64
  },
50
65
  "devDependencies": {
51
66
  "@capacitor/android": "^8.3.1",
@@ -76,7 +91,8 @@
76
91
  "rollup": "^4.60.2",
77
92
  "semantic-release": "^25.0.3",
78
93
  "swiftlint": "^2.0.0",
79
- "typescript": "^5.9.3"
94
+ "typescript": "~6.0.3",
95
+ "vitest": "^4.1.10"
80
96
  },
81
97
  "peerDependencies": {
82
98
  "@capacitor/core": ">=8.0.0"