Files
linkster-ios/Linkster/QRScannerView.swift
2026-04-19 19:55:22 +02:00

63 lines
2.0 KiB
Swift

import SwiftUI
import AVFoundation
struct QRScannerView: UIViewControllerRepresentable {
let onScan: (String) -> Void
func makeUIViewController(context: Context) -> ScannerViewController {
let vc = ScannerViewController()
vc.onScan = onScan
return vc
}
func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {}
}
final class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var onScan: ((String) -> Void)?
private let session = AVCaptureSession()
private var previewLayer: AVCaptureVideoPreviewLayer?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
setupCapture()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
previewLayer?.frame = view.bounds
}
private func setupCapture() {
guard let device = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: device),
session.canAddInput(input) else { return }
session.addInput(input)
let output = AVCaptureMetadataOutput()
guard session.canAddOutput(output) else { return }
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue: .main)
output.metadataObjectTypes = [.qr]
let layer = AVCaptureVideoPreviewLayer(session: session)
layer.videoGravity = .resizeAspectFill
view.layer.addSublayer(layer)
previewLayer = layer
DispatchQueue.global(qos: .userInitiated).async { self.session.startRunning() }
}
func metadataOutput(_ output: AVCaptureMetadataOutput,
didOutput objects: [AVMetadataObject],
from connection: AVCaptureConnection) {
guard let obj = objects.first as? AVMetadataMachineReadableCodeObject,
let value = obj.stringValue else { return }
session.stopRunning()
onScan?(value)
}
}