63 lines
2.0 KiB
Swift
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)
|
|
}
|
|
}
|