AV Foundation is the full featured framework for working with time-based audiovisual media on iOS, macOS, watchOS and tvOS. Using AV Foundation, you can easily play, create, and edit QuickTime movies and MPEG-4 files, play HLS streams, and build powerful media functionality into your apps.
AVFoundation incorporates, the ability to discover and read bar codes in real-time. Any barcode scanning, including QR codes, is totally based on video capturing, that’s why AVFoundation framework supports the barcode reading feature. Keep this info on mind, as it’s the starting point for the entire application.
First of all add UIView view, which is going to be the container for the preview layer of the video captured by the device.
Here is how the demo application is going to work:
Add the camera button on the UIViewController. When you will click on this button a UIView will be loaded that will contain the preview of recording. When you will start recording any Barcode , it will capture it and display the information captured on UITextField.
Also, a sound effect (a beep sound) is being played every time a QR code has been successfully read to make our app more vivid and interactive.
Note that this application cannot be tested on the Simulator, neither to a device without a camera, as everything is based on real-time video capturing. Therefore, you’ll need to connect your device and run it there if you want to see the application live.
First of all make XIB that contains a UIView with Black BackGround, as shown below
Make a class named "QRScanView"
Add following code in "QRScanView.h"
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface QRScanView : UIView <AVCaptureMetadataOutputObjectsDelegate>
// connect your Xib here
@property (weak, nonatomic) IBOutlet UIView *scanView;
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property BOOL isReading;
@property void(^barCodeScanned)(NSString*);
+ (instancetype) loadScanner;
- (void)showScanner:(UIViewController*) vc;
- (void) getScannedValue:(void(^)(NSString* message))callback;
@end
Add following code in "QRScanView.m"
// remove Xib from view here
#import "QRScanView.h"
static QRScanView* sSharedInstance;
static QRScanView* _scanner ;
@interface QRScanView()
{
NSString* _serviceTag;
}
@end
@implementation QRScanView
+ (instancetype) loadScanner
{
if(!sSharedInstance)
{
// load your xib on UIView here
// load your xib on UIView here
sSharedInstance = [[[NSBundle mainBundle] loadNibNamed:@"QRScanView" owner:sSharedInstance options:nil] lastObject];
}
return sSharedInstance;
}
- (void)showScanner:(UIViewController*) vc
{
sSharedInstance.isReading = NO;
sSharedInstance.captureSession = nil;
sSharedInstance.center = CGPointMake(vc.view.frame.size.width / 2,
vc.view.frame.size.height / 2);
sSharedInstance.layer.borderWidth = 1.0f;
sSharedInstance.layer.borderColor = [UIColor lightGrayColor].CGColor;
[sSharedInstance startReading];
[vc.view addSubview:sSharedInstance];
}
- (void) startReading
{
NSError *error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input)
{
NSLog(@"%@", [error localizedDescription]);
}
_captureSession = [[AVCaptureSession alloc] init];
[_captureSession addInput:input];
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[_captureSession addOutput:captureMetadataOutput];
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("myQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
// include all types of barcode here
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeQRCode, AVMetadataObjectTypeFace, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeUPCECode,AVMetadataObjectTypeAztecCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeITF14Code,AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeDataMatrixCode,AVMetadataObjectTypeCode39Mod43Code,AVMetadataObjectTypeInterleaved2of5Code, nil]];
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:self.scanView.layer.bounds];
[self.scanView.layer addSublayer:_videoPreviewLayer];
[_captureSession startRunning];
}
- (void) stopReading
{
[_captureSession stopRunning];
_captureSession = nil;
[_videoPreviewLayer removeFromSuperlayer];
// remove Xib from view here
[self removeFromSuperview];
self.barCodeScanned(_serviceTag);
}
// get scanned value here
- (void) getScannedValue:(void(^)(NSString* message))callback
{
self.barCodeScanned = callback;
}
// Delegate methods for AVCaptureMetadataOutputObjects
- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
if (metadataObjects != nil && [metadataObjects count] > 0)
{
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
_serviceTag = [metadataObj stringValue];
[self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];
self.isReading = NO;
}
}
@end
Now import "BarcodeScan.h" file in you ViewController
On IBAction of button click, call the method of "QRScanView" class like this
- (IBAction)scanCodeBtnPressed:(id)sender
{
QRScanView* scanner = [QRScanView loadScanner];
self.scanCodeBtn.selected = !self.scanCodeBtn.isSelected;
if(self.scanCodeBtn.selected)
[scanner showScanner:self];
[scanner getScannedValue:^(NSString *message) {
//display scanner message on UITextField
UITextField* textField = (UITextField*)[self.view viewWithTag:EServiceTag];
textField.text = message;
}];
}
0 comments:
Post a Comment