I have barcode scanning working in my app. After the barcode is detected I stop the capture session to allow processing of the barcode. However, after the barcode is processed I want the scanning controller to stay up and the next barcode scanned. I had assumed that starting the capture session (startRunning()) would do it but the image stays frozen. How can I start the capture session again?
4 Answers
To Stop The Session use this code
self.session.stopRunning() To begin it agian, use this code
self.session.startRunning() Here is all the code to implement a barcode scanner...
import UIKit import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { let session : AVCaptureSession = AVCaptureSession() var previewLayer : AVCaptureVideoPreviewLayer! var highlightView : UIView = UIView() override func viewDidLoad() { super.viewDidLoad() // Allow the view to resize freely self.highlightView.autoresizingMask = UIViewAutoresizing.FlexibleTopMargin | UIViewAutoresizing.FlexibleBottomMargin | UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleRightMargin // Select the color you want for the completed scan reticle self.highlightView.layer.borderColor = UIColor.greenColor().CGColor self.highlightView.layer.borderWidth = 3 // Add it to our controller's view as a subview. self.view.addSubview(self.highlightView) // For the sake of discussion this is the camera let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) // Create a nilable NSError to hand off to the next method. // Make sure to use the "var" keyword and not "let" var error : NSError? = nil let input : AVCaptureDeviceInput? = AVCaptureDeviceInput.deviceInputWithDevice(device, error: &error) as? AVCaptureDeviceInput // If our input is not nil then add it to the session, otherwise we're kind of done! if input != nil { session.addInput(input) } else { // This is fine for a demo, do something real with this in your app. :) println(error) } let output = AVCaptureMetadataOutput() output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) session.addOutput(output) output.metadataObjectTypes = output.availableMetadataObjectTypes previewLayer = AVCaptureVideoPreviewLayer.layerWithSession(session) as! AVCaptureVideoPreviewLayer previewLayer.frame = self.view.bounds previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill self.view.layer.addSublayer(previewLayer) // Start the scanner. You'll have to end it yourself later. session.startRunning() } // This is called when we find a known barcode type with the camera. func captureOutput( captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { var highlightViewRect = CGRectZero var barCodeObject : AVMetadataObject! var detectionString : String! let barCodeTypes = [AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode] // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan. for metadata in metadataObjects { for barcodeType in barCodeTypes { if metadata.type == barcodeType { barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject) highlightViewRect = barCodeObject.bounds detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue self.session.stopRunning() self.alert(detectionString) break } } } println(detectionString) self.highlightView.frame = highlightViewRect self.view.bringSubviewToFront(self.highlightView) } func alert(Code: String){ let actionSheet:UIAlertController = UIAlertController( title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.Alert) // for alert add .Alert instead of .Action Sheet // start copy let firstAlertAction:UIAlertAction = UIAlertAction( title: "OK", style: UIAlertActionStyle.Default, handler: { (alertAction: UIAlertAction!) in // action when pressed self.session.startRunning() }) actionSheet.addAction(firstAlertAction) // end copy self.presentViewController(actionSheet, animated: true, completion: nil) } } 2 Comments
Floyd Resler
I was doing pretty much the same thing but I had two lines of code swapped. I was sending the result string to my handler and then stopping the session. It wouldn't restart. If I stopped the session before sending the results to my handler then it worked.
mkhoshpour
Added Swift 3 version here: stackoverflow.com/a/41512546/2108523
edited the above code for swift 2.0:
import UIKit import AVFoundation class BarCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { let session : AVCaptureSession = AVCaptureSession() var previewLayer : AVCaptureVideoPreviewLayer! @IBOutlet weak var highlightView: UIView! override func viewDidLoad() { super.viewDidLoad() // Select the color you want for the completed scan reticle self.highlightView.layer.borderColor = UIColor.greenColor().CGColor self.highlightView.layer.borderWidth = 3 // Add it to our controller's view as a subview. self.view.addSubview(self.highlightView) // For the sake of discussion this is the camera let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) // Create a nilable NSError to hand off to the next method. // Make sure to use the "var" keyword and not "let" var error : NSError? = nil var input: AVCaptureDeviceInput = AVCaptureDeviceInput() do { input = try AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput } catch let myJSONError { print(myJSONError) } // If our input is not nil then add it to the session, otherwise we're kind of done! if input != AVCaptureDeviceInput() { session.addInput(input) } else { // This is fine for a demo, do something real with this in your app. :) print(error) } let output = AVCaptureMetadataOutput() output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) session.addOutput(output) output.metadataObjectTypes = output.availableMetadataObjectTypes previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = self.view.bounds previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill self.view.layer.addSublayer(previewLayer) // Start the scanner. You'll have to end it yourself later. session.startRunning() } // This is called when we find a known barcode type with the camera. func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { var highlightViewRect = CGRectZero var barCodeObject : AVMetadataObject! var detectionString : String! let barCodeTypes = [AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode ] // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan. for metadata in metadataObjects { for barcodeType in barCodeTypes { if metadata.type == barcodeType { barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject) highlightViewRect = barCodeObject.bounds detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue self.session.stopRunning() self.alert(detectionString) break } } } print(detectionString) self.highlightView.frame = highlightViewRect self.view.bringSubviewToFront(self.highlightView) } func alert(Code: String){ let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.Alert) // for alert add .Alert instead of .Action Sheet // start copy let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (alertAction:UIAlertAction!) in // action when pressed self.session.startRunning() }) actionSheet.addAction(firstAlertAction) // end copy self.presentViewController(actionSheet, animated: true, completion: nil) } } Comments
Swift 3.0 version:
import UIKit import AVFoundation class BarCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { let session : AVCaptureSession = AVCaptureSession() var previewLayer : AVCaptureVideoPreviewLayer! @IBOutlet weak var highlightView: UIView! override func viewDidLoad() { super.viewDidLoad() self.highlightView.layer.borderColor = UIColor.green.cgColor self.highlightView.layer.borderWidth = 3 // Add it to our controller's view as a subview. self.view.addSubview(self.highlightView) // For the sake of discussion this is the camera let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) // Create a nilable NSError to hand off to the next method. // Make sure to use the "var" keyword and not "let" var error : NSError? = nil var input: AVCaptureDeviceInput = AVCaptureDeviceInput() do { input = try AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput } catch let myJSONError { print(myJSONError) } // If our input is not nil then add it to the session, otherwise we're kind of done! if input != AVCaptureDeviceInput() { session.addInput(input) } else { // This is fine for a demo, do something real with this in your app. :) print(error!) } let output = AVCaptureMetadataOutput() output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) session.addOutput(output) output.metadataObjectTypes = output.availableMetadataObjectTypes previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = self.view.bounds previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill self.view.layer.addSublayer(previewLayer) // Start the scanner. You'll have to end it yourself later. session.startRunning() } // This is called when we find a known barcode type with the camera. @nonobjc func captureOutput( captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { var highlightViewRect = CGRect() var barCodeObject : AVMetadataObject! var detectionString : String! let barCodeTypes = [AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode] // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan. for metadata in metadataObjects { for barcodeType in barCodeTypes { if metadata.type == barcodeType { barCodeObject = self.previewLayer.transformedMetadataObject(for: metadata as! AVMetadataMachineReadableCodeObject) highlightViewRect = barCodeObject.bounds detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue self.session.stopRunning() self.alert(Code: detectionString) break } } } print(detectionString) self.highlightView.frame = highlightViewRect self.view.bringSubview(toFront: self.highlightView) } func alert(Code: String){ let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.alert) // for alert add .Alert instead of .Action Sheet // start copy let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (alertAction: UIAlertAction!) in // action when pressed self.session.startRunning() }) actionSheet.addAction(firstAlertAction) // end copy self.present(actionSheet, animated: true, completion: nil) } } Comments
Swift 5 update
func captureOutput( captureOutput: AVCaptureOutput, didOutputMetadataObjects metadataObjects: [AnyObject], fromConnection connection: AVCaptureConnection, barCodeType: [AVMetadataObject.ObjectType]) -> String? { var detectionString: String? var highlightViewRect = CGRect() let barCodeTypes = barCodeType if let metadataObject = metadataObjects.first { for barcodeType in barCodeTypes { if metadataObject.type == barcodeType { guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return String()} guard let barCodeObject = self.previewLayer.transformedMetadataObject(for: readableObject) else { return String()} highlightViewRect = barCodeObject.bounds detectionString = readableObject.stringValue self.captureSession.stopRunning() break } } } self.qrView.frame = highlightViewRect self.view.bringSubviewToFront(self.qrView) return detectionString } 1 Comment
javi_swift
Downvote as this is only a partial port of the accepted answer.