From fc13f4a0851705d04cce55bd305cda8c513b9dd5 Mon Sep 17 00:00:00 2001 From: heping Date: Fri, 6 Jun 2025 19:09:02 +0800 Subject: [PATCH 1/2] =?UTF-8?q?1.fix=20a=20bug=EF=BC=88qrOutput=20can=20no?= =?UTF-8?q?t=20be=20removed,=20as=20it's=20not=20stored=20after=20creation?= =?UTF-8?q?=EF=BC=89=202.extend=20startQRCodeDetection=EF=BC=8Csupport=20c?= =?UTF-8?q?ustomize=20metadata=20types=20and=20keep=20compatibility.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/CameraManager.swift | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Sources/CameraManager.swift b/Sources/CameraManager.swift index a568cea..174a0fe 100644 --- a/Sources/CameraManager.swift +++ b/Sources/CameraManager.swift @@ -795,7 +795,7 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest /** Start detecting QR codes. */ - open func startQRCodeDetection(_ handler: @escaping QRCodeDetectionHandler) { + open func startQRCodeDetection(withTypes types: [AVMetadataObject.ObjectType] = [.qr, .ean8, .ean13, .pdf417], _ handler: @escaping QRCodeDetectionHandler) { guard let captureSession = self.captureSession else { return } @@ -805,11 +805,17 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest else { return } qrCodeDetectionHandler = handler - captureSession.addOutput(output) - // Note: The object types must be set after the output was added to the capture session. - output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) - output.metadataObjectTypes = [.qr, .ean8, .ean13, .pdf417].filter { output.availableMetadataObjectTypes.contains($0) } + sessionQueue.async { + captureSession.beginConfiguration() + captureSession.addOutput(output) + // Note: The object types must be set after the output was added to the capture session. + output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) + assert(captureSession.inputs.count ?? 0 > 0, "Error: output.availableMetadataObjectTypes is available only after adding input.") + output.metadataObjectTypes = types.filter { output.availableMetadataObjectTypes.contains($0) } + captureSession.commitConfiguration() + } + qrOutput = output //add this line, for removing when stopped } /** @@ -832,7 +838,7 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest /** The stored meta data output; used to detect QR codes. */ - private var qrOutput: AVCaptureOutput? + open private(set) var qrOutput: AVCaptureMetadataOutput? /** Check if the device rotation is locked From 61e0f53191bfb2d07ef639de474a7bc0f4826887 Mon Sep 17 00:00:00 2001 From: heping Date: Wed, 16 Jul 2025 15:02:43 +0800 Subject: [PATCH 2/2] fix: put session stop operation into the session queue to keep the session state consistent --- .gitignore | 1 + Sources/CameraManager.swift | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ba487e2..d1b04f0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ ## Build generated build/ DerivedData +.build ## Various settings *.pbxuser diff --git a/Sources/CameraManager.swift b/Sources/CameraManager.swift index 174a0fe..f5c7664 100644 --- a/Sources/CameraManager.swift +++ b/Sources/CameraManager.swift @@ -454,8 +454,15 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest Stops running capture session but all setup devices, inputs and outputs stay for further reuse. */ open func stopCaptureSession() { - captureSession?.stopRunning() - _stopFollowingDeviceOrientation() + if let validCaptureSession = captureSession { + if validCaptureSession.isRunning, cameraIsSetup { + sessionQueue.async { [weak self] in + guard let self = self else { return } + self.captureSession?.stopRunning() + self._stopFollowingDeviceOrientation() + } + } + } } /**