투케이2K

248. (ios/swift) AVCaptureSession , AVCaptureVideoPreviewLayer 사용해 카메라 QR 및 바코드 스캐너 만들기 본문

IOS

248. (ios/swift) AVCaptureSession , AVCaptureVideoPreviewLayer 사용해 카메라 QR 및 바코드 스캐너 만들기

투케이2K 2022. 11. 7. 12:18

[개발 환경 설정]

개발 툴 : XCODE

개발 언어 : SWIFT

 

[사전 준비]

 

[호출 : 소스 코드]

    // MARK: - [테스트 메인 함수 정의 실시]
    func testMain() {
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> testMain() :: 테스트 함수 시작 실시]")
        print("====================================")
        print("")
        
        
        /*
         // -----------------------------
         [요약 설명]
         // -----------------------------
         1. 사전 info plist 설정 :
         
         Privacy - Camera Usage Description
         // -----------------------------
         2. 필요 import :
         
         import AVKit
         // -----------------------------
         */
        
        
        // [비동기 처리 수행]
        DispatchQueue.main.async {
            
            // [카메라 사용 권한 확인]
            let status = AVCaptureDevice.authorizationStatus(for: .video)
            if (status == .authorized) {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [허용] [1]]")
                print("====================================")
                print("")
                
                DispatchQueue.main.async {
                    
                    // [카메라 열기]
                    DispatchQueue.main.async {
                        
                        // [카메라 열기]
                        if #available(iOS 13.0, *) {
                            guard let A_CameraVC = self.storyboard?.instantiateViewController(identifier:"A_CameraVC") as? A_Camera
                            else {
                                return
                            }
                                    
                            A_CameraVC.modalPresentationStyle = .fullScreen // 전체화면 (기본은 팝업형태)
                            self.present(A_CameraVC, animated: false, completion: nil) // 인텐트 이동 실시
                        }
                        // -----------------------------------------
                        else {
                            guard let A_CameraVC = self.storyboard?.instantiateViewController(withIdentifier:"A_CameraVC") as? A_Camera
                            else {
                                return
                            }
                                    
                            A_CameraVC.modalPresentationStyle = .fullScreen // 전체화면 (기본은 팝업형태)
                            self.present(A_CameraVC, animated: false, completion: nil) // 인텐트 이동 실시
                        }

                    }
                }
            }
            else if (status == .denied) {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [거부] [1]]")
                print("====================================")
                print("")
            }
            else if (status == .notDetermined) {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [대기]]")
                print("====================================")
                print("")
                
                // [권한 요청 실시]
                AVCaptureDevice.requestAccess(for: .video) { (isSuccess) in
                    if (isSuccess) {
                        print("")
                        print("====================================")
                        print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [허용] [2]]")
                        print("====================================")
                        print("")
                        
                        DispatchQueue.main.async {
                            
                            // [카메라 열기]
                            if #available(iOS 13.0, *) {
                                guard let A_CameraVC = self.storyboard?.instantiateViewController(identifier:"A_CameraVC") as? A_Camera
                                else {
                                    return
                                }
                                        
                                A_CameraVC.modalPresentationStyle = .fullScreen // 전체화면 (기본은 팝업형태)
                                self.present(A_CameraVC, animated: false, completion: nil) // 인텐트 이동 실시
                            }
                            // -----------------------------------------
                            else {
                                guard let A_CameraVC = self.storyboard?.instantiateViewController(withIdentifier:"A_CameraVC") as? A_Camera
                                else {
                                    return
                                }
                                        
                                A_CameraVC.modalPresentationStyle = .fullScreen // 전체화면 (기본은 팝업형태)
                                self.present(A_CameraVC, animated: false, completion: nil) // 인텐트 이동 실시
                            }

                        }
                        
                    }
                    else {
                        print("")
                        print("====================================")
                        print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [거부] [2]]")
                        print("====================================")
                        print("")
                    }
                }
            }
            else {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> testMain() :: 카메라 사용 권한 [ELSE]]")
                print("====================================")
                print("")
            }
        }
    }
 

[카메라 : 소스 코드]

import UIKit
import Foundation
import AVKit
import AVFoundation

class A_Camera: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    
    
    // MARK: - [전역 변수 선언 실시]
    let ACTIVITY_NAME = "A_Camera"
    
    
    
    
    
    // MARK: - [뷰 로드 실시]
    override func viewDidLoad() {
        super.viewDidLoad()
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidLoad() :: 뷰 로드 실시]")
        print("====================================")
        print("")
        
        // [배경 색상 지정]
        self.view.backgroundColor = .black
        
        // [카메라 열기 실시]
        self.openCamera()
    }
    
    
    
    
    
    // MARK: - [뷰 로드 완료]
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewWillAppear() :: 뷰 로드 완료]")
        print("====================================")
        print("")
    }
        
    
    
    
    
    // MARK: - [뷰 화면 표시]
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidAppear() :: 뷰 화면 표시]")
        print("====================================")
        print("")
        
    }
        
    
    
    
    
    // MARK: - [뷰 정지 상태]
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewWillDisappear() :: 뷰 정지 상태]")
        print("====================================")
        print("")
    }
        
    
    
    
    
    // MARK: - [뷰 종료 상태]
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> viewDidDisappear() :: 뷰 종료 상태]")
        print("====================================")
        print("")
    }
    
    
    
    
    
    // MARK: - [QR 및 바코드 스캔 실시]
    var captureSession: AVCaptureSession?
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    func openCamera(){
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> openCamera() :: 카메라 열기 수행]")
        print("====================================")
        print("")
        
        let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
        if let captureDevice = captureDevice {
            do {
                self.captureSession = AVCaptureSession()
                
                let input: AVCaptureDeviceInput
                input = try AVCaptureDeviceInput(device: captureDevice)
                self.captureSession?.addInput(input)
                
                
                let metadataOutput = AVCaptureMetadataOutput()
                self.captureSession?.addOutput(metadataOutput)
                metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                metadataOutput.metadataObjectTypes = [.qr, .code128] // MARK: [스캔 형식 지정]
                
                
                self.videoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession!)
                self.videoPreviewLayer?.videoGravity = .resizeAspectFill
                
                let uiView = UIView()
                uiView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
                
                
                self.videoPreviewLayer?.frame = CGRect(x: 0, y: 0, width: uiView.bounds.width, height: uiView.bounds.height)
                uiView.layer.addSublayer(self.videoPreviewLayer!)
                self.view.addSubview(uiView)
                
                
                DispatchQueue.global().async {
                    self.captureSession?.startRunning()
                }
                
                
            } catch {
                print("")
                print("====================================")
                print("[\(self.ACTIVITY_NAME) >> openCamera() :: catch 에러 발생]")
                print("====================================")
                print("")
            }
        }
    }
    
    
    
    
    
    // MARK: - [스캔 결과 확인]
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        
        // [스캔 종료]
        DispatchQueue.global().async {
            self.captureSession!.stopRunning()
        }
        
        // [스캔 결과 없음]
        if metadataObjects.count == 0 {
            return
        }
        
        // [스캔 데이터 확인]
        let metaDataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
        guard let StringCodeValue = metaDataObject.stringValue else {
            return
        }
        guard let _ = self.videoPreviewLayer?.transformedMetadataObject(for: metaDataObject) else {
            return
        }
        
        
        // [부모 뷰에서 카메라 레이아웃 제거]
        self.videoPreviewLayer?.removeFromSuperlayer()
        self.view.removeFromSuperview()
        
     
        // [스캔 결과 출력]
        print("")
        print("====================================")
        print("[\(self.ACTIVITY_NAME) >> metadataOutput() :: 카메라 스캔 결과 확인]")
        print("StringCodeValue :: \(StringCodeValue)")
        print("====================================")
        print("")
        
        
        // MARK: [화면 닫기 실시]
        self.dismiss(animated: false)
    }
    
    
} // [클래스 종료]
 

[결과 출력]

 

 

반응형
Comments