Created
March 11, 2019 06:40
-
-
Save abhimuralidharan/765ecaf95cbae67de81236b0786bf59f to your computer and use it in GitHub Desktop.
QRCode scanner in iOS swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// QRScannerView.swift | |
// QRCodeReader | |
// | |
// Created by KM, Abhilash a on 08/03/19. | |
// Copyright © 2019 KM, Abhilash. All rights reserved. | |
// | |
import Foundation | |
import UIKit | |
import AVFoundation | |
/// Delegate callback for the QRScannerView. | |
protocol QRScannerViewDelegate: class { | |
func qrScanningDidFail() | |
func qrScanningSucceededWithCode(_ str: String?) | |
func qrScanningDidStop() | |
} | |
class QRScannerView: UIView { | |
weak var delegate: QRScannerViewDelegate? | |
/// capture settion which allows us to start and stop scanning. | |
var captureSession: AVCaptureSession? | |
// Init methods.. | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
doInitialSetup() | |
} | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
doInitialSetup() | |
} | |
//MARK: overriding the layerClass to return `AVCaptureVideoPreviewLayer`. | |
override class var layerClass: AnyClass { | |
return AVCaptureVideoPreviewLayer.self | |
} | |
override var layer: AVCaptureVideoPreviewLayer { | |
return super.layer as! AVCaptureVideoPreviewLayer | |
} | |
} | |
extension QRScannerView { | |
var isRunning: Bool { | |
return captureSession?.isRunning ?? false | |
} | |
func startScanning() { | |
captureSession?.startRunning() | |
} | |
func stopScanning() { | |
captureSession?.stopRunning() | |
delegate?.qrScanningDidStop() | |
} | |
/// Does the initial setup for captureSession | |
private func doInitialSetup() { | |
clipsToBounds = true | |
captureSession = AVCaptureSession() | |
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return } | |
let videoInput: AVCaptureDeviceInput | |
do { | |
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) | |
} catch let error { | |
print(error) | |
return | |
} | |
if (captureSession?.canAddInput(videoInput) ?? false) { | |
captureSession?.addInput(videoInput) | |
} else { | |
scanningDidFail() | |
return | |
} | |
let metadataOutput = AVCaptureMetadataOutput() | |
if (captureSession?.canAddOutput(metadataOutput) ?? false) { | |
captureSession?.addOutput(metadataOutput) | |
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) | |
metadataOutput.metadataObjectTypes = [.qr, .ean8, .ean13, .pdf417] | |
} else { | |
scanningDidFail() | |
return | |
} | |
self.layer.session = captureSession | |
self.layer.videoGravity = .resizeAspectFill | |
captureSession?.startRunning() | |
} | |
func scanningDidFail() { | |
delegate?.qrScanningDidFail() | |
captureSession = nil | |
} | |
func found(code: String) { | |
delegate?.qrScanningSucceededWithCode(code) | |
} | |
} | |
extension QRScannerView: AVCaptureMetadataOutputObjectsDelegate { | |
func metadataOutput(_ output: AVCaptureMetadataOutput, | |
didOutput metadataObjects: [AVMetadataObject], | |
from connection: AVCaptureConnection) { | |
stopScanning() | |
if let metadataObject = metadataObjects.first { | |
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return } | |
guard let stringValue = readableObject.stringValue else { return } | |
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) | |
found(code: stringValue) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment