Skip to content

Instantly share code, notes, and snippets.

@abhimuralidharan
Created March 11, 2019 06:40
Show Gist options
  • Save abhimuralidharan/765ecaf95cbae67de81236b0786bf59f to your computer and use it in GitHub Desktop.
Save abhimuralidharan/765ecaf95cbae67de81236b0786bf59f to your computer and use it in GitHub Desktop.
QRCode scanner in iOS swift
//
// 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