XLOG

[SwiftUI] QR Code Scanner 만들기 (SwifUI 에 ViewController 사용하기) 본문

Swift/SwiftUI

[SwiftUI] QR Code Scanner 만들기 (SwifUI 에 ViewController 사용하기)

X_PROFIT 2023. 3. 8. 20:43

SwiftUI 만으론 QR Code Scanner를 만들 수 없다......

그 이유는 UIKit Framework 가 필요하다. AVFoundation, AVCaptureMetadataOutputObjectsDelegate 를 사용하기 위해서......

 

우선 AVFoundation 은 swift 에서 제공하는 Audio, Video 를 다루기 위한 frameworkd 다.

여기서의 핵심은  AVCaptureSession 을 사용하는 것이다.

디바이스로 부터 들어온 데이터를 출력해주는 세션, 즉 input 과 Output을 연결해주는 역할을 한다.

 

우리는 이 센션에 AVCaptureDeviceInput 을 Input으로 추가, 가져온 메타데이터를 위해 AVCaptureMetadataOutput 을 ouput에 추가해 준다. AVCaptureMetadataOutput 에 델리게이트를 설정해주면 읽어온 데이터 처리가 가능하다. 또한 읽어온 객체타입을 설정할 수 있는데, 기본정으로 Apple에서 ML Model이 장착되어 있는제 얼굴, 사람의몸 등 다양한 것을 읽을 수 잇다.

 

private func settting() {
        guard let captureDevice = AVCaptureDevice.default(for: .video) else {
            fatalError("No Video")
        }
        do {
            // QR코드를 인식할 영역 값
            let rectOfInterest = CGRect(x: (UIScreen.main.bounds.width - 200) / 2 , y: (view.bounds.height - width * 1.4) / 2 + 100 , width: 200, height: 200)
            
            // cameraDevice를 설정하여 AVCaptureSEssion에 input 으로 추가
            let input = try AVCaptureDeviceInput(device: captureDevice)
            captureSession.addInput(input)
            
            // Input으로 들어온 데이터를 metadata로 출력하기 위해 AVCapturMetadataOutput 을 세션에 추가
            let output = AVCaptureMetadataOutput()
            captureSession.addOutput(output)
            
            // 메타데이터를 읽을 때 동작할 델리게이트 붙여주기
            output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            // 메타데이터의 타입 설정, humanBody, dogBody, face 등등 다양하게 있음
            output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
            let rectConverted = setVideoLayer(rectOfInterest: rectOfInterest)
            
            // QR코드 인식 영역 설정
            output.rectOfInterest = rectConverted
            
            // QR코드 인식 영역 프레임 그리기
            setGuideCrossLineView(rectOfInterest: rectOfInterest)
            
            // session 은 background thread 에서 동작해야 하여 GCD를 이용하여 background qod thread 에서 동작할 수 있도록....
            DispatchQueue.global(qos: .background).async {
                self.captureSession.startRunning()
            }
            
        } catch {
            print("error")
        }
extension QRCodeReaderViewController: AVCaptureMetadataOutputObjectsDelegate {
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject, let stringValue = readableObject.stringValue else {
                return
            }
            // URL 주소의 QR 코드 값이 읽힐 때만 Label 변경
            if stringValue.hasPrefix("http://") || stringValue.hasPrefix("https://")  {
                labelView.text = stringValue
            }
        }
    }
}

또한 메디타이터를 처리하기 위한 Delegate 설정이 필요하다.

 

이렇게 QR Code Reader View Controller 가 준비가 되었으면 우리는 UIViewControllerRepresentable 를 사용하여 SwiftUI 가 인식할 수 있는 View로 다시 만들어 줘야 한다.

struct QRCodeReaderViewRepresentable: UIViewControllerRepresentable {
    
    typealias UIViewControllerType = QRCodeReaderViewController
    
    func makeUIViewController(context: Context) -> QRCodeReaderViewController {
        let qr = QRCodeReaderViewController()
        return qr
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    }
}

이렇게 생성된 구조체를 ContentView에서 사용하면 끝이다.

 

참고로 AVFoundation 에서 카메라를 사용하기 위해서 

info.plist 에서 Privacy - Camera Usage Description 을 통해 카메라 권한을 받는걸 잊으면 안된다.

 

  1. 참고 : https://developer.apple.com/documentation/avfoundation
  2. 참고 : https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable
  3. 참고 : https://gyuios.tistory.com/79
  4. 참고 : https://nebori.tistory.com/28
  5. 참고 : https://hururuek-chapchap.tistory.com/34
  6. 참고 : https://blog.devgenius.io/camera-preview-and-a-qr-code-scanner-in-swiftui-48b111155c66

Github: https://github.com/profit0124/QRCodeScanner-SwiftUI