Scanning Barcodes and QR Codes with AVFoundation on iOS7+

With the release of iOS 7, Apple included the ability to detect barcodes through its AVFoundation framework. It is really easy to add barcode scanning to your app without using any additional libraries.

We just need to create a capture session so we can trigger the camera when needed. We set the input for the capture session to our capture device (the device camera). The output is an AVCaptureMetadataOutput object which takes care of reading the metadata from camera input. This is the core step of reading the bar codes. To see what the camera captures, we can add a preview layer to the controller’s view and attach it to the camera. Finally, to start scanning, start the session and you are done. The delegate methods will be called when a barcode is detected.

// Find the input for default capture device
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
    NSLog(@"%@", [error localizedDescription]);
    return NO;
}

// Create a capture session and add input
self.captureSession = [[AVCaptureSession alloc] init];
[self.captureSession addInput:input];

// Add the session output
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[self.captureSession addOutput:captureMetadataOutput];

// Configure the metadata output
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("barcodeReaderQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode39Code]];

// Add a preview layer to see camera preview
self.videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
[self.videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[self.videoPreviewLayer setFrame:self.previewView.layer.bounds];
[self.previewView.layer addSublayer:self.videoPreviewLayer];

// Start running the capture session
[self.captureSession startRunning];

The delegate method captureOutput:didOutputMetadataObjects:fromConnection: is called everytime a metadata object is processed. From here, we can extract the string value of the metadata object to get the barcode string.

#pragma mark - Capture Metadata Output Objects Delegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSString *barcodeString = metadataObj.stringValue;
        NSLog(@"Read barcode: %@", barcodeString);
    }
}
Published 12 Oct 2014

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter