Fix black screen on QR scanner after first camera permission grant.
Update preview layer layout and session lifecycle when authorization completes asynchronously. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -14,6 +14,7 @@ final class QRCodeScannerViewController: BaseViewController, AVCaptureMetadataOu
|
||||
|
||||
private let captureSession = AVCaptureSession()
|
||||
private var previewLayer: AVCaptureVideoPreviewLayer?
|
||||
private var isCameraConfigured = false
|
||||
private var hasHandledResult = false
|
||||
|
||||
private let maskView = UIView()
|
||||
@ -60,17 +61,21 @@ final class QRCodeScannerViewController: BaseViewController, AVCaptureMetadataOu
|
||||
checkCameraPermission()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
updatePreviewLayout()
|
||||
startCaptureSessionIfNeeded()
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
previewLayer?.frame = view.bounds
|
||||
updatePreviewLayout()
|
||||
updateMask()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
if captureSession.isRunning {
|
||||
captureSession.stopRunning()
|
||||
}
|
||||
stopCaptureSession()
|
||||
}
|
||||
|
||||
private func checkCameraPermission() {
|
||||
@ -94,11 +99,21 @@ final class QRCodeScannerViewController: BaseViewController, AVCaptureMetadataOu
|
||||
}
|
||||
|
||||
private func setupCamera() {
|
||||
if isCameraConfigured {
|
||||
updatePreviewLayout()
|
||||
startCaptureSessionIfNeeded()
|
||||
return
|
||||
}
|
||||
|
||||
guard let device = AVCaptureDevice.default(for: .video),
|
||||
let input = try? AVCaptureDeviceInput(device: device) else {
|
||||
showToast("无法打开相机")
|
||||
return
|
||||
}
|
||||
|
||||
captureSession.beginConfiguration()
|
||||
defer { captureSession.commitConfiguration() }
|
||||
|
||||
guard captureSession.canAddInput(input) else { return }
|
||||
captureSession.addInput(input)
|
||||
|
||||
@ -112,12 +127,30 @@ final class QRCodeScannerViewController: BaseViewController, AVCaptureMetadataOu
|
||||
layer.videoGravity = .resizeAspectFill
|
||||
view.layer.insertSublayer(layer, at: 0)
|
||||
previewLayer = layer
|
||||
isCameraConfigured = true
|
||||
|
||||
updatePreviewLayout()
|
||||
startCaptureSessionIfNeeded()
|
||||
}
|
||||
|
||||
private func updatePreviewLayout() {
|
||||
previewLayer?.frame = view.bounds
|
||||
}
|
||||
|
||||
private func startCaptureSessionIfNeeded() {
|
||||
guard isCameraConfigured, !captureSession.isRunning else { return }
|
||||
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
||||
self?.captureSession.startRunning()
|
||||
}
|
||||
}
|
||||
|
||||
private func stopCaptureSession() {
|
||||
guard captureSession.isRunning else { return }
|
||||
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
||||
self?.captureSession.stopRunning()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMask() {
|
||||
maskView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
|
||||
let border = CAShapeLayer()
|
||||
@ -139,7 +172,7 @@ final class QRCodeScannerViewController: BaseViewController, AVCaptureMetadataOu
|
||||
let value = object.stringValue,
|
||||
!value.isEmpty else { return }
|
||||
hasHandledResult = true
|
||||
captureSession.stopRunning()
|
||||
stopCaptureSession()
|
||||
onScanResult?(value)
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user