Notice
Recent Posts
Recent Comments
Link
투케이2K
403. (ios/swift5) [유틸 파일] observable_Qr_Barcode_Scan : QR , Barcode 스캔 수행 실시 - AVCaptureDevice 본문
IOS
403. (ios/swift5) [유틸 파일] observable_Qr_Barcode_Scan : QR , Barcode 스캔 수행 실시 - AVCaptureDevice
투케이2K 2023. 12. 21. 19:56[개발 환경 설정]
개발 툴 : XCODE
개발 언어 : SWIFT5
[소스 코드]
// -----------------------------------------------------------------------------------------
// MARK: - [전역 변수 선언]
// -----------------------------------------------------------------------------------------
private let ACTIVITY_NAME = "C_Ui_View"
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
let scanOperationQueue = OperationQueue()
var scanFlag = false
var scanResult = ""
// MARK: - [extension 정의 실시 : 뷰 컨트롤러]
extension UIViewController: AVCaptureMetadataOutputObjectsDelegate {
// -----------------------------------------------------------------------------------------
// MARK: - [QR 및 Barcode 스캔 팝업창 호출 메소드]
// -----------------------------------------------------------------------------------------
func observable_Qr_Barcode_Scan(title:String, okBtn:String, callback: @escaping (String) -> ()) {
/*
// -----------------------------------------
[observable_Qr_Barcode_Scan 메소드 설명]
// -----------------------------------------
1. QR 및 Barcode 스캔 팝업창 호출 메소드
// -----------------------------------------
2. info plist 설정 :
Privacy - Camera Usage Description
// -----------------------------------------
3. 필요 import 설정 :
import AVKit
// -----------------------------------------
4. 호출 방법 :
self.observable_Qr_Barcode_Scan(title: "Qr 및 Barcode 스캔", okBtn:"닫기"){(result) in
S_Log._D_(description: "Qr 및 Barcode 스캔 콜백 결과 확인", data: ["\(result)"])
// [팝업창 표시]
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if C_Util().stringNotNull(str: "\(result)") == true {
self.showAlert(
type: 0,
tittle: "Qr 및 Barcode 스캔 콜백 결과 확인",
content: "\(result)",
okBtb: "확인",
noBtn: ""
)
}
}
}
// -----------------------------------------
*/
// [작업 큐에 추가]
scanResult = ""
scanOperationQueue.isSuspended = true
let block = { callback(scanResult) } // [콜백 데이터]
scanOperationQueue.addOperation(block)
// [메인 큐에서 비동기 방식 실행 : UI 동작 실시]
DispatchQueue.main.async {
S_Log._D_(description: "QR 및 Barcode 스캔 팝업창 호출 수행 실시", data: [
"tittle :: \(title)"
])
// [변수 초기화]
scanFlag = false
// [UIAlertController 생성]
let alert = UIAlertController(
title: title,
message: "",
preferredStyle: .alert
)
// [닫기 버튼 등록 실시]
if C_Util().stringNotNull(str: okBtn) == true {
let okAction = UIAlertAction(title: okBtn, style: .default) { (action) in
// [스캔 중지]
if captureSession != nil {
captureSession?.stopRunning() // [스캔 종료]
}
// [콜백 반환]
scanOperationQueue.isSuspended = false
// [버튼 클릭 이벤트 내용 정의 실시]
return
}
// [버튼 클릭 이벤트 객체 연결]
alert.addAction(okAction)
}
// [AVCaptureDevice 생성]
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
if let captureDevice = captureDevice {
do {
captureSession = AVCaptureSession()
let input: AVCaptureDeviceInput
input = try AVCaptureDeviceInput(device: captureDevice)
captureSession?.addInput(input)
let metadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(metadataOutput) // [결과 출력 지정]
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.qr, .code128] // MARK: [스캔 형식 지정]
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
videoPreviewLayer?.videoGravity = .resizeAspectFill
let uiView = UIView()
uiView.frame = CGRect(x: alert.view.frame.width/15, y: alert.view.frame.width/5, width: alert.view.frame.width-150, height: alert.view.frame.width-150)
videoPreviewLayer?.frame = CGRect(x: 0, y: 0, width: uiView.frame.width, height: uiView.frame.height)
uiView.layer.addSublayer(videoPreviewLayer!)
alert.view.addSubview(uiView) // [팝업창에 추가]
// [Alert LayoutConstraint]
let height = NSLayoutConstraint(item: alert.view!, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: alert.view.frame.width)
let width = NSLayoutConstraint(item: alert.view!, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: alert.view.frame.width-100)
alert.view.addConstraint(height)
alert.view.addConstraint(width)
DispatchQueue.global().async {
captureSession?.startRunning() // [스캔 시작]
}
} catch {
S_Log._D_(description: "QR 및 Barcode 스캔 팝업창 에러 발생", data: [
"Exception :: \(error.localizedDescription)"
])
alert.message = "[Exception] : \(error.localizedDescription)"
}
}
else {
S_Log._D_(description: "QR 및 Barcode 스캔 팝업창 에러 발생", data: [
"Error :: AVCaptureDevice Is Nil"
])
alert.message = "[Error] : AVCaptureDevice Is Nil"
}
// [alert 팝업창 활성 실시]
self.present(alert, animated: false, completion: nil)
}
}
// -----------------------------------------------------------------------------------------
// [AVCaptureMetadataOutputObjectsDelegate : Delegate] : 카메라 스캔 콜백
// -----------------------------------------------------------------------------------------
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
DispatchQueue.main.async {
if scanFlag == false {
// [스캔 플래그 값 변경]
scanFlag = true
// [스캔 결과 없음]
if metadataObjects.count == 0 {
scanFlag = false // [스캔 플래그 값 변경]
return
}
// [스캔 데이터 확인]
let metaDataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
guard let StringCodeValue = metaDataObject.stringValue else {
scanFlag = false // [스캔 플래그 값 변경]
return
}
guard let _ = videoPreviewLayer?.transformedMetadataObject(for: metaDataObject) else {
scanFlag = false // [스캔 플래그 값 변경]
return
}
// [널 체크 수행]
if C_Util().stringNotNull(str: StringCodeValue) == true { // [널 아님]
// [스캔 결과 확인]
S_Log._D_(description: "QR 및 Barcode 스캔 결과 확인", data: [
"\(StringCodeValue)"
])
scanResult = "\(StringCodeValue)"
// [결과 표시 Alert 팝업창 표시]
let scan = UIAlertController(
title: "QR 및 Barcode 스캔 결과",
message: "\(scanResult)",
preferredStyle: .alert
)
// [스캔 관련 객체 초기화]
DispatchQueue.global().async {
captureSession?.stopRunning() // [스캔 종료]
}
// [스캔창 팝업창 닫기]
self.dismiss(animated: false)
// [콜백 반환]
scanOperationQueue.isSuspended = false
}
else {
S_Log._D_(description: "QR 및 Barcode 스캔 결과 : Data Is Null", data: nil)
}
}
}
}
} // [extension 종료]
[결과 출력]
반응형