capacitor-camera-view 2.0.0 → 2.0.2

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.
@@ -11,7 +11,7 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
11
11
  .builtInDualCamera,
12
12
  .builtInDualWideCamera,
13
13
  .builtInTripleCamera,
14
- .builtInTrueDepthCamera
14
+ .builtInTrueDepthCamera,
15
15
  ]
16
16
 
17
17
  /// A camera implementation that handles camera session management and photo capture.
@@ -66,8 +66,12 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
66
66
  webView: UIView,
67
67
  completion: @escaping (Error?) -> Void
68
68
  ) {
69
- if let preferredCameraDeviceTypes = configuration.preferredCameraDeviceTypes {
70
- self.preferredCameraDeviceTypes = convertToNativeCameraTypes(preferredCameraDeviceTypes)
69
+ if let preferredCameraDeviceTypes = configuration
70
+ .preferredCameraDeviceTypes
71
+ {
72
+ self.preferredCameraDeviceTypes = convertToNativeCameraTypes(
73
+ preferredCameraDeviceTypes
74
+ )
71
75
  }
72
76
 
73
77
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
@@ -110,29 +114,35 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
110
114
  await self.upgradeToTripleCameraIfAvailable()
111
115
  }
112
116
  }
113
- })
117
+ }
118
+ )
114
119
  }
115
120
  }
116
121
 
117
122
  /// Stops the current capture session.
118
- public func stopSession() {
119
- guard captureSession.isRunning else { return }
123
+ public func stopSession(completion: (() -> Void)? = nil) {
124
+ guard captureSession.isRunning else {
125
+ completion?()
126
+ return
127
+ }
120
128
 
121
129
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
122
130
  self?.captureSession.stopRunning()
123
- }
124
131
 
125
- DispatchQueue.main.async { [weak self] in
126
- guard let self = self else { return }
127
- self.videoPreviewLayer.removeFromSuperlayer()
128
- self.webView?.isOpaque = true
129
- self.webView?.backgroundColor = nil
130
- self.webView = nil
131
-
132
- if let blurOverlayView = self.blurOverlayView {
133
- blurOverlayView.removeFromSuperview()
134
- self.blurOverlayView = nil
132
+ DispatchQueue.main.async { [weak self] in
133
+ guard let self = self else { return }
134
+ self.videoPreviewLayer.removeFromSuperlayer()
135
+ self.webView?.isOpaque = true
136
+ self.webView?.backgroundColor = nil
137
+ self.webView = nil
138
+
139
+ if let blurOverlayView = self.blurOverlayView {
140
+ blurOverlayView.removeFromSuperview()
141
+ self.blurOverlayView = nil
142
+ }
135
143
  }
144
+
145
+ completion?()
136
146
  }
137
147
  }
138
148
 
@@ -163,9 +173,11 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
163
173
 
164
174
  // Ensure proper orientation
165
175
  if let photoConnection = avPhotoOutput.connection(with: .video),
166
- let previewConnection = videoPreviewLayer.connection {
176
+ let previewConnection = videoPreviewLayer.connection
177
+ {
167
178
  if photoConnection.isVideoOrientationSupported {
168
- photoConnection.videoOrientation = previewConnection.videoOrientation
179
+ photoConnection.videoOrientation =
180
+ previewConnection.videoOrientation
169
181
  }
170
182
  }
171
183
 
@@ -176,7 +188,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
176
188
  /// Capture a snapshot of the current camera view. This is faster than actually processing a
177
189
  /// photo via capturePhoto
178
190
  /// - Parameter completion: called with the captured UIImage or an error.
179
- public func captureSnapshot(completion: @escaping (UIImage?, Error?) -> Void) {
191
+ public func captureSnapshot(
192
+ completion: @escaping (UIImage?, Error?) -> Void
193
+ ) {
180
194
  guard currentCameraDevice != nil else {
181
195
  completion(nil, CameraError.cameraUnavailable)
182
196
  return
@@ -189,24 +203,33 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
189
203
 
190
204
  // Ensure proper orientation
191
205
  if let videoConnection = avVideoDataOutput.connection(with: .video),
192
- let previewConnection = videoPreviewLayer.connection {
206
+ let previewConnection = videoPreviewLayer.connection
207
+ {
193
208
  if videoConnection.isVideoOrientationSupported {
194
- videoConnection.videoOrientation = previewConnection.videoOrientation
209
+ videoConnection.videoOrientation =
210
+ previewConnection.videoOrientation
195
211
  }
196
212
  }
197
213
 
198
214
  // Create a serial queue for sample buffer processing
199
- let sampleBufferQueue = DispatchQueue(label: "com.michaelwolz.capacitorcameraview.snapshotQueue")
215
+ let sampleBufferQueue = DispatchQueue(
216
+ label: "com.michaelwolz.capacitorcameraview.snapshotQueue"
217
+ )
200
218
 
201
219
  // Set the delegate for a single frame capture
202
220
  snapshotCompletionHandler = completion
203
- avVideoDataOutput.setSampleBufferDelegate(self, queue: sampleBufferQueue)
221
+ avVideoDataOutput.setSampleBufferDelegate(
222
+ self,
223
+ queue: sampleBufferQueue
224
+ )
204
225
  }
205
226
 
206
227
  /// Flips the camera to the opposite position (front to back or back to front).
207
228
  public func flipCamera() throws {
208
- let currentPosition: AVCaptureDevice.Position = currentCameraDevice?.position ?? .back
209
- let newPosition: AVCaptureDevice.Position = currentPosition == .back ? .front : .back
229
+ let currentPosition: AVCaptureDevice.Position =
230
+ currentCameraDevice?.position ?? .back
231
+ let newPosition: AVCaptureDevice.Position =
232
+ currentPosition == .back ? .front : .back
210
233
 
211
234
  let newCamera = try getCameraDevice(for: newPosition)
212
235
  try setInput(with: newCamera)
@@ -217,7 +240,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
217
240
  /// - Parameter mode: The desired flash mode (.on, .of, or .auto).
218
241
  /// - Throws: An error if the flash mode cannot be set or is not supported.
219
242
  public func setFlashMode(_ mode: AVCaptureDevice.FlashMode) throws {
220
- guard let camera = currentCameraDevice else { throw CameraError.cameraUnavailable }
243
+ guard let camera = currentCameraDevice else {
244
+ throw CameraError.cameraUnavailable
245
+ }
221
246
  guard camera.hasFlash else { throw CameraError.unsupportedFlashMode }
222
247
  guard avPhotoOutput.supportedFlashModes.contains(mode)
223
248
  else {
@@ -270,7 +295,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
270
295
  /// - level: The torch intensity level (0.0 to 1.0)
271
296
  /// - Throws: An error if the torch mode cannot be set or is not supported.
272
297
  public func setTorchMode(enabled: Bool, level: Float = 1.0) throws {
273
- guard let camera = currentCameraDevice else { throw CameraError.cameraUnavailable }
298
+ guard let camera = currentCameraDevice else {
299
+ throw CameraError.cameraUnavailable
300
+ }
274
301
  guard camera.hasTorch else { throw CameraError.torchUnavailable }
275
302
 
276
303
  do {
@@ -292,7 +319,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
292
319
  /// because some devices report very high zoom factors that aren't useful.
293
320
  ///
294
321
  /// - Returns: A tuple containing the minimum, maximum, and current zoom factors.
295
- public func getSupportedZoomFactors() -> (min: CGFloat, max: CGFloat, current: CGFloat) {
322
+ public func getSupportedZoomFactors() -> (
323
+ min: CGFloat, max: CGFloat, current: CGFloat
324
+ ) {
296
325
  guard let currentDevice = currentCameraDevice else {
297
326
  return (
298
327
  min: 1.0,
@@ -302,7 +331,10 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
302
331
  }
303
332
 
304
333
  let minZoomFactor = currentDevice.minAvailableVideoZoomFactor
305
- let maxZoomFactor = min(currentDevice.activeFormat.videoMaxZoomFactor, 10.0)
334
+ let maxZoomFactor = min(
335
+ currentDevice.activeFormat.videoMaxZoomFactor,
336
+ 10.0
337
+ )
306
338
  let currentZoomFactor = currentDevice.videoZoomFactor
307
339
 
308
340
  return (
@@ -319,10 +351,15 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
319
351
  /// - ramp: If enabled the zoom will be applied via ramp
320
352
  /// - Throws: An error if the zoom factor cannot be set.
321
353
  public func setZoomFactor(_ factor: CGFloat, ramp: Bool = true) throws {
322
- guard let device = currentCameraDevice else { throw CameraError.cameraUnavailable }
354
+ guard let device = currentCameraDevice else {
355
+ throw CameraError.cameraUnavailable
356
+ }
323
357
 
324
358
  let supportedZoomFactors = getSupportedZoomFactors()
325
- guard factor >= supportedZoomFactors.min && factor <= supportedZoomFactors.max else {
359
+ guard
360
+ factor >= supportedZoomFactors.min
361
+ && factor <= supportedZoomFactors.max
362
+ else {
326
363
  throw CameraError.zoomFactorOutOfRange
327
364
  }
328
365
 
@@ -344,7 +381,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
344
381
  ///
345
382
  /// - Parameters:
346
383
  /// - configuration: The configuration object for the camera session.
347
- private func initiateCaptureSession(configuration: CameraSessionConfiguration) throws {
384
+ private func initiateCaptureSession(
385
+ configuration: CameraSessionConfiguration
386
+ ) throws {
348
387
  captureSession.beginConfiguration()
349
388
  defer { captureSession.commitConfiguration() }
350
389
 
@@ -413,7 +452,6 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
413
452
  }
414
453
  }
415
454
 
416
-
417
455
  /// Enables barcode detection by adding metadata output to the running session.
418
456
  /// Somehow adding the metadata output with the session not being started yet
419
457
  /// caused issues on some devices (iPad 7th Gen) where the session would just
@@ -463,19 +501,26 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
463
501
  /// - position: The position of the camera device to get
464
502
  /// - Returns: The camera device for the specified position
465
503
  /// - Throws: An error if no camera device is found.
466
- private func getCameraDevice(for position: AVCaptureDevice.Position?) throws -> AVCaptureDevice {
504
+ private func getCameraDevice(for position: AVCaptureDevice.Position?) throws
505
+ -> AVCaptureDevice
506
+ {
467
507
  let preferredDevices = getPreferredCameraDevices()
468
508
 
469
509
  // First try to get the best match based on the users preferred camera device types
470
- if let match = preferredDevices.first(where: { $0.position == position }) {
510
+ if let match = preferredDevices.first(where: { $0.position == position }
511
+ ) {
471
512
  return match
472
513
  }
473
514
 
474
515
  // If we haven't found one we try to get a best match for the position by iterating all supported device types
475
516
  // Only doing this when preferredCameraDeviceTypes size differs from SUPPORTED_CAMERA_DEVICE_TYPES, otherwise
476
517
  // we don't have to initialize a new discovery session
477
- if preferredCameraDeviceTypes.count < SUPPORTED_CAMERA_DEVICE_TYPES.count,
478
- let match = getAvailableDevices().first(where: { $0.position == position }) {
518
+ if preferredCameraDeviceTypes.count
519
+ < SUPPORTED_CAMERA_DEVICE_TYPES.count,
520
+ let match = getAvailableDevices().first(where: {
521
+ $0.position == position
522
+ })
523
+ {
479
524
  return match
480
525
  }
481
526
 
@@ -485,8 +530,12 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
485
530
  }
486
531
 
487
532
  // Log when we're falling back to a device with different position than requested
488
- if let requestedPosition = position, device.position != requestedPosition {
489
- print("Warning: Falling back to camera at position \(device.position) when \(requestedPosition) was requested")
533
+ if let requestedPosition = position,
534
+ device.position != requestedPosition
535
+ {
536
+ print(
537
+ "Warning: Falling back to camera at position \(device.position) when \(requestedPosition) was requested"
538
+ )
490
539
  }
491
540
 
492
541
  return device
@@ -498,8 +547,14 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
498
547
  /// - deviceId: The unique identifier of the camera device to get
499
548
  /// - Returns: The camera device for the specified position
500
549
  /// - Throws: An error if no camera device is found.
501
- private func getCameraDeviceById(_ deviceId: String) throws -> AVCaptureDevice {
502
- guard let device = getAvailableDevices().first(where: { $0.uniqueID == deviceId }) else {
550
+ private func getCameraDeviceById(_ deviceId: String) throws
551
+ -> AVCaptureDevice
552
+ {
553
+ guard
554
+ let device = getAvailableDevices().first(where: {
555
+ $0.uniqueID == deviceId
556
+ })
557
+ else {
503
558
  throw CameraError.cameraUnavailable
504
559
  }
505
560
  return device
@@ -514,7 +569,10 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
514
569
  /// - view: The view that will display the camera preview.
515
570
  /// - completion: The completion handler after successfully adding the previewLayer to the provided view
516
571
  /// - Throws: An error if the preview layer cannot be set up.
517
- private func displayPreview(on view: UIView, completion: @escaping (Error?) -> Void) {
572
+ private func displayPreview(
573
+ on view: UIView,
574
+ completion: @escaping (Error?) -> Void
575
+ ) {
518
576
  guard captureSession.isRunning else {
519
577
  completion(CameraError.sessionNotRunning)
520
578
  return
@@ -575,7 +633,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
575
633
  try self.setZoomFactor(2.0, ramp: false)
576
634
  } catch {
577
635
  // Fail silently if we can't upgrade to the triple camera
578
- print("Failed to upgrade to triple camera: \(error.localizedDescription)")
636
+ print(
637
+ "Failed to upgrade to triple camera: \(error.localizedDescription)"
638
+ )
579
639
  }
580
640
 
581
641
  self.captureSession.commitConfiguration()
@@ -607,7 +667,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
607
667
  /// Removes the blur overlay with a fade out animation to have a smooth transition
608
668
  /// - Parameter duration: The duration of the fade out animation
609
669
  @MainActor
610
- private func removeBlurOverlayWithAnimation(duration: TimeInterval = 0.3) async {
670
+ private func removeBlurOverlayWithAnimation(duration: TimeInterval = 0.3)
671
+ async
672
+ {
611
673
  guard let blurEffectView = blurOverlayView else { return }
612
674
 
613
675
  await withCheckedContinuation { continuation in
@@ -620,7 +682,8 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
620
682
  blurEffectView.removeFromSuperview()
621
683
  self.blurOverlayView = nil
622
684
  continuation.resume()
623
- })
685
+ }
686
+ )
624
687
  }
625
688
  }
626
689
 
@@ -639,11 +702,15 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
639
702
 
640
703
  /// Updates the preview layer orientation based on the current device orientation.
641
704
  private func updatePreviewOrientation() {
642
- guard let connection = self.videoPreviewLayer.connection, connection.isVideoOrientationSupported else {
705
+ guard let connection = self.videoPreviewLayer.connection,
706
+ connection.isVideoOrientationSupported
707
+ else {
643
708
  return
644
709
  }
645
710
 
646
- let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait
711
+ let interfaceOrientation =
712
+ UIApplication.shared.windows.first?.windowScene?
713
+ .interfaceOrientation ?? .portrait
647
714
  let videoOrientation: AVCaptureVideoOrientation
648
715
 
649
716
  switch interfaceOrientation {
@@ -683,7 +750,8 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
683
750
  self,
684
751
  selector: #selector(handleAppDidBecomeActive),
685
752
  name: UIApplication.didBecomeActiveNotification,
686
- object: nil)
753
+ object: nil
754
+ )
687
755
  }
688
756
 
689
757
  /// Handles the app going to background by pausing the camera session.
@@ -95,8 +95,9 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin {
95
95
  }
96
96
 
97
97
  @objc func stop(_ call: CAPPluginCall) {
98
- implementation.stopSession()
99
- call.resolve()
98
+ implementation.stopSession {
99
+ call.resolve()
100
+ }
100
101
  }
101
102
 
102
103
  @objc func isRunning(_ call: CAPPluginCall) {
@@ -316,7 +317,7 @@ public class CameraViewPlugin: CAPPlugin, CAPBridgedPlugin {
316
317
  }
317
318
 
318
319
  let level = call.getFloat("level") ?? 1.0
319
-
320
+
320
321
  guard level >= 0.0 && level <= 1.0 else {
321
322
  call.reject("Level must be between 0.0 and 1.0")
322
323
  return
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-camera-view",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
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",