capacitor-camera-module 0.0.68 → 0.0.69

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.
@@ -5,29 +5,26 @@ import UIKit
5
5
  import Photos
6
6
 
7
7
  @objc(CameraModule)
8
- public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOutputSampleBufferDelegate {
9
-
10
-
11
- public let identifier = "CameraModule"
12
- public let jsName = "CameraModule"
13
- public let pluginMethods: [CAPPluginMethod] = [
14
- CAPPluginMethod(name: "checkPermission", returnType: CAPPluginReturnPromise),
15
- CAPPluginMethod(name: "requestPermission", returnType: CAPPluginReturnPromise),
16
- CAPPluginMethod(name: "checkGalleryPermission", returnType: CAPPluginReturnPromise),
17
- CAPPluginMethod(name: "requestGalleryPermission", returnType: CAPPluginReturnPromise),
18
- CAPPluginMethod(name: "checkAndRequestGalleryPermission", returnType: CAPPluginReturnPromise),
19
- CAPPluginMethod(name: "pickImageBase64", returnType: CAPPluginReturnPromise),
20
- CAPPluginMethod(name: "startPreview", returnType: CAPPluginReturnPromise),
21
- CAPPluginMethod(name: "stopPreview", returnType: CAPPluginReturnPromise),
22
- CAPPluginMethod(name: "toggleFlash", returnType: CAPPluginReturnPromise),
23
- CAPPluginMethod(name: "hasFlash", returnType: CAPPluginReturnPromise),
24
- CAPPluginMethod(name: "takePhotoBase64", returnType: CAPPluginReturnPromise),
25
- CAPPluginMethod(name: "startBarcodeScan", returnType: CAPPluginReturnPromise),
26
- CAPPluginMethod(name: "stopBarcodeScan", returnType: CAPPluginReturnPromise),
27
- CAPPluginMethod(name: "getLastGalleryImage", returnType: CAPPluginReturnPromise)
28
-
29
- ]
30
-
8
+ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoDataOutputSampleBufferDelegate {
9
+
10
+ public let identifier = "CameraModule"
11
+ public let jsName = "CameraModule"
12
+ public let pluginMethods: [CAPPluginMethod] = [
13
+ CAPPluginMethod(name: "checkPermission", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "requestPermission", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "checkGalleryPermission", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "requestGalleryPermission", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "checkAndRequestGalleryPermission", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "pickImageBase64", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "startPreview", returnType: CAPPluginReturnPromise),
20
+ CAPPluginMethod(name: "stopPreview", returnType: CAPPluginReturnPromise),
21
+ CAPPluginMethod(name: "toggleFlash", returnType: CAPPluginReturnPromise),
22
+ CAPPluginMethod(name: "hasFlash", returnType: CAPPluginReturnPromise),
23
+ CAPPluginMethod(name: "takePhotoBase64", returnType: CAPPluginReturnPromise),
24
+ CAPPluginMethod(name: "startBarcodeScan", returnType: CAPPluginReturnPromise),
25
+ CAPPluginMethod(name: "stopBarcodeScan", returnType: CAPPluginReturnPromise),
26
+ CAPPluginMethod(name: "getLastGalleryImage", returnType: CAPPluginReturnPromise)
27
+ ]
31
28
 
32
29
  private var previewView: UIView?
33
30
  private var captureSession: AVCaptureSession?
@@ -51,13 +48,9 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
51
48
 
52
49
  // MARK: - Lifecycle
53
50
  public override func load() {
54
- // Este método ya no fuerza el color negro
55
- // El webView será configurado dinámicamente en startPreview/stopPreview
56
51
  print("📱 CameraModulePlugin cargado")
57
52
  }
58
53
 
59
-
60
-
61
54
  // MARK: - Camera Permission
62
55
 
63
56
  @objc func checkPermission(_ call: CAPPluginCall) {
@@ -142,107 +135,106 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
142
135
 
143
136
  // MARK: - Camera Preview
144
137
 
145
- @objc func startPreview(_ call: CAPPluginCall) {
146
- DispatchQueue.main.async {
147
- if self.previewView != nil {
148
- call.resolve()
149
- return
150
- }
138
+ @objc func startPreview(_ call: CAPPluginCall) {
139
+ DispatchQueue.main.async {
140
+ if self.previewView != nil {
141
+ call.resolve()
142
+ return
143
+ }
151
144
 
152
- guard AVCaptureDevice.authorizationStatus(for: .video) == .authorized else {
153
- call.reject("Camera permission not granted")
154
- return
155
- }
145
+ guard AVCaptureDevice.authorizationStatus(for: .video) == .authorized else {
146
+ call.reject("Camera permission not granted")
147
+ return
148
+ }
156
149
 
157
- let session = AVCaptureSession()
150
+ let session = AVCaptureSession()
158
151
 
159
- guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
160
- let input = try? AVCaptureDeviceInput(device: device) else {
161
- call.reject("Camera not available")
162
- return
163
- }
152
+ guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
153
+ let input = try? AVCaptureDeviceInput(device: device) else {
154
+ call.reject("Camera not available")
155
+ return
156
+ }
164
157
 
165
- if session.canAddInput(input) {
166
- session.addInput(input)
167
- }
158
+ if session.canAddInput(input) {
159
+ session.addInput(input)
160
+ }
168
161
 
169
- if session.canAddOutput(self.photoOutput) {
170
- session.addOutput(self.photoOutput)
171
- }
162
+ if session.canAddOutput(self.photoOutput) {
163
+ session.addOutput(self.photoOutput)
164
+ }
172
165
 
173
- guard let container = self.bridge?.viewController?.view else {
174
- call.reject("No container view")
175
- return
176
- }
166
+ guard let container = self.bridge?.viewController?.view else {
167
+ call.reject("No container view")
168
+ return
169
+ }
177
170
 
178
- guard let webView = self.bridge?.webView as? WKWebView else {
179
- call.reject("No webView")
180
- return
181
- }
171
+ guard let webView = self.bridge?.webView as? WKWebView else {
172
+ call.reject("No webView")
173
+ return
174
+ }
182
175
 
183
- // 1. Hacer el webView transparente
184
- webView.isOpaque = false
185
- webView.backgroundColor = .clear
186
- webView.scrollView.backgroundColor = .clear
187
- webView.scrollView.isOpaque = false
188
-
189
- // 2. Crear previewView
190
- let previewView = UIView()
191
- previewView.translatesAutoresizingMaskIntoConstraints = false
192
- previewView.backgroundColor = .clear // Transparente desde el inicio
193
- previewView.isUserInteractionEnabled = false // No intercepta toques
194
-
195
- // 3. Insertar previewView DETRÁS de todo
196
- container.insertSubview(previewView, at: 0)
197
-
198
- // 4. Configurar constraints para toda la pantalla
199
- NSLayoutConstraint.activate([
200
- previewView.topAnchor.constraint(equalTo: container.topAnchor),
201
- previewView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
202
- previewView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
203
- previewView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
204
- ])
176
+ // 1. Hacer el webView transparente
177
+ webView.isOpaque = false
178
+ webView.backgroundColor = .clear
179
+ webView.scrollView.backgroundColor = .clear
180
+ webView.scrollView.isOpaque = false
181
+
182
+ // 2. Crear previewView
183
+ let previewView = UIView()
184
+ previewView.translatesAutoresizingMaskIntoConstraints = false
185
+ previewView.backgroundColor = .clear // Transparente desde el inicio
186
+ previewView.isUserInteractionEnabled = false // No intercepta toques
187
+
188
+ // 3. Insertar previewView DETRÁS de todo
189
+ container.insertSubview(previewView, at: 0)
190
+
191
+ // 4. Configurar constraints para toda la pantalla
192
+ NSLayoutConstraint.activate([
193
+ previewView.topAnchor.constraint(equalTo: container.topAnchor),
194
+ previewView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
195
+ previewView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
196
+ previewView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
197
+ ])
205
198
 
206
- // 5. Asegurar orden de capas
207
- previewView.layer.zPosition = -1 // Detrás de todo
208
- webView.layer.zPosition = 0 // Normal
199
+ // 5. Asegurar orden de capas
200
+ previewView.layer.zPosition = -1 // Detrás de todo
201
+ webView.layer.zPosition = 0 // Normal
209
202
 
210
- // 6. Forzar layout
211
- container.layoutIfNeeded()
203
+ // 6. Forzar layout
204
+ container.layoutIfNeeded()
212
205
 
213
- // 7. Crear previewLayer
214
- let previewLayer = AVCaptureVideoPreviewLayer(session: session)
215
- previewLayer.videoGravity = .resizeAspectFill
216
- previewLayer.frame = previewView.bounds
217
- previewLayer.masksToBounds = true
206
+ // 7. Crear previewLayer
207
+ let previewLayer = AVCaptureVideoPreviewLayer(session: session)
208
+ previewLayer.videoGravity = .resizeAspectFill
209
+ previewLayer.frame = previewView.bounds
210
+ previewLayer.masksToBounds = true
218
211
 
219
- previewView.layer.insertSublayer(previewLayer, at: 0)
212
+ previewView.layer.insertSublayer(previewLayer, at: 0)
220
213
 
221
- // 8. Guardar referencias
222
- self.previewView = previewView
223
- self.videoPreviewLayer = previewLayer
224
- self.captureSession = session
214
+ // 8. Guardar referencias
215
+ self.previewView = previewView
216
+ self.videoPreviewLayer = previewLayer
217
+ self.captureSession = session
225
218
 
226
- // 9. Configurar sesión
227
- session.sessionPreset = .photo
219
+ // 9. Configurar sesión
220
+ session.sessionPreset = .photo
228
221
 
229
- // 10. Iniciar sesión en background
230
- DispatchQueue.global(qos: .userInitiated).async {
231
- session.startRunning()
222
+ // 10. Iniciar sesión en background
223
+ DispatchQueue.global(qos: .userInitiated).async {
224
+ session.startRunning()
232
225
 
233
- DispatchQueue.main.async {
234
- print("Cámara iniciada correctamente")
235
- print("Preview visible: \(previewView.window != nil ? "SÍ" : "NO")")
226
+ DispatchQueue.main.async {
227
+ print("Cámara iniciada correctamente")
228
+ print("Preview visible: \(previewView.window != nil ? "SÍ" : "NO")")
229
+ }
236
230
  }
237
- }
238
231
 
239
- call.resolve([
240
- "success": true,
241
- "message": "Preview de cámara iniciado"
242
- ])
232
+ call.resolve([
233
+ "success": true,
234
+ "message": "Preview de cámara iniciado"
235
+ ])
236
+ }
243
237
  }
244
- }
245
-
246
238
 
247
239
  @objc func stopPreview(_ call: CAPPluginCall) {
248
240
  DispatchQueue.main.async {
@@ -286,9 +278,6 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
286
278
  }
287
279
  }
288
280
 
289
-
290
-
291
-
292
281
  // MARK: - Flash
293
282
 
294
283
  @objc func toggleFlash(_ call: CAPPluginCall) {
@@ -317,49 +306,49 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
317
306
 
318
307
  @objc func getLastGalleryImage(_ call: CAPPluginCall) {
319
308
 
320
- let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
309
+ let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
321
310
 
322
- guard status == .authorized || status == .limited else {
323
- call.reject("Gallery permission not granted")
324
- return
325
- }
311
+ guard status == .authorized || status == .limited else {
312
+ call.reject("Gallery permission not granted")
313
+ return
314
+ }
326
315
 
327
- let fetchOptions = PHFetchOptions()
328
- fetchOptions.sortDescriptors = [
329
- NSSortDescriptor(key: "creationDate", ascending: false)
330
- ]
331
- fetchOptions.fetchLimit = 1
316
+ let fetchOptions = PHFetchOptions()
317
+ fetchOptions.sortDescriptors = [
318
+ NSSortDescriptor(key: "creationDate", ascending: false)
319
+ ]
320
+ fetchOptions.fetchLimit = 1
332
321
 
333
- let assets = PHAsset.fetchAssets(with: .image, options: fetchOptions)
322
+ let assets = PHAsset.fetchAssets(with: .image, options: fetchOptions)
334
323
 
335
- guard let asset = assets.firstObject else {
336
- call.reject("No images found")
337
- return
338
- }
324
+ guard let asset = assets.firstObject else {
325
+ call.reject("No images found")
326
+ return
327
+ }
339
328
 
340
- let imageManager = PHImageManager.default()
341
- let options = PHImageRequestOptions()
342
- options.isSynchronous = true
343
- options.deliveryMode = .highQualityFormat
344
- options.resizeMode = .none
329
+ let imageManager = PHImageManager.default()
330
+ let options = PHImageRequestOptions()
331
+ options.isSynchronous = true
332
+ options.deliveryMode = .highQualityFormat
333
+ options.resizeMode = .none
345
334
 
346
- imageManager.requestImageDataAndOrientation(
347
- for: asset,
348
- options: options
349
- ) { data, _, _, _ in
335
+ imageManager.requestImageDataAndOrientation(
336
+ for: asset,
337
+ options: options
338
+ ) { data, _, _, _ in
350
339
 
351
- guard let imageData = data else {
352
- call.reject("Error fetching last image")
353
- return
354
- }
340
+ guard let imageData = data else {
341
+ call.reject("Error fetching last image")
342
+ return
343
+ }
355
344
 
356
- let base64 = imageData.base64EncodedString()
345
+ let base64 = imageData.base64EncodedString()
357
346
 
358
- var ret = JSObject()
359
- ret["base64"] = base64
360
- call.resolve(ret)
361
- }
347
+ var ret = JSObject()
348
+ ret["base64"] = base64
349
+ call.resolve(ret)
362
350
  }
351
+ }
363
352
 
364
353
  // MARK: - Photo Capture
365
354
 
@@ -434,7 +423,7 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
434
423
  let output = AVCaptureVideoDataOutput()
435
424
  output.videoSettings = [
436
425
  kCVPixelBufferPixelFormatTypeKey as String:
437
- kCVPixelFormatType_32BGRA
426
+ kCVPixelFormatType_32BGRA
438
427
  ]
439
428
  output.alwaysDiscardsLateVideoFrames = true
440
429
  output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "barcode.queue"))
@@ -478,9 +467,35 @@ public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOu
478
467
  try? handler.perform([request])
479
468
  }
480
469
 
470
+ // MARK: - PhotoDelegate Class
481
471
 
482
- // MARK: - UIImagePicker Delegate
472
+ private class PhotoDelegate: NSObject, AVCapturePhotoCaptureDelegate {
473
+ private let completion: (String) -> Void
474
+
475
+ init(completion: @escaping (String) -> Void) {
476
+ self.completion = completion
477
+ }
478
+
479
+ func photoOutput(_ output: AVCapturePhotoOutput,
480
+ didFinishProcessingPhoto photo: AVCapturePhoto,
481
+ error: Error?) {
482
+ if let error = error {
483
+ print("Error capturando foto: \(error)")
484
+ return
485
+ }
486
+
487
+ guard let data = photo.fileDataRepresentation(),
488
+ let base64 = data.base64EncodedString() as? String else {
489
+ print("No se pudo convertir la imagen a base64")
490
+ return
491
+ }
492
+
493
+ completion(base64)
494
+ }
495
+ }
496
+ }
483
497
 
498
+ // MARK: - UIImagePicker Delegate
484
499
  extension CameraModulePlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
485
500
 
486
501
  public func imagePickerController(_ picker: UIImagePickerController,
@@ -511,7 +526,6 @@ extension CameraModulePlugin: UIImagePickerControllerDelegate, UINavigationContr
511
526
  }
512
527
 
513
528
  // MARK: - UIImage Resize
514
-
515
529
  extension UIImage {
516
530
  func resized(maxSize: CGFloat) -> UIImage? {
517
531
  let maxSide = max(size.width, size.height)
@@ -526,6 +540,4 @@ extension UIImage {
526
540
  UIGraphicsEndImageContext()
527
541
  return img
528
542
  }
529
-
530
-
531
- }
543
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-camera-module",
3
- "version": "0.0.68",
3
+ "version": "0.0.69",
4
4
  "description": "Plugin to request permissiones view camera take phots",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",