使用 AVFoundation 實現 QRCode 掃描
note : only available after ios7
AVCaptureMetadataOutput 在 ios7 擴充了能夠辨識一維條碼和二維條碼的功能
而目前 zxing 似乎也還不支援 arm64 的架構
因此若 app 只打算支援 ios7 以上的話
可以考慮使用此方式實作 QRCode 掃描功能
Code 很單純從頭到尾僅使用一個 UIViewController
另外使用 ARC 機制的請記得將 release 的部份註解或拿掉 >.0
MainViewController.h#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface MainViewController : UIViewController<AVCaptureMetadataOutputObjectsDelegate>
-(IBAction)buttonScan:(id)sender;
-(BOOL)startScan;
-(void)stopScan;
@end
@implementation MainViewController{
UIView *view_fore; //前景用來放置工具列
UIView *view_back; //後景用來顯示Camera的畫面
UILabel *label_value; //顯示 QRCode 的資料
UIBarButtonItem *baritem_start; //掃描跟停止的 Button
bool bool_reading; //判斷是否正在掃描的 boolean
AVCaptureSession *captureSession; //Captrue連結
AVCaptureVideoPreviewLayer *videoPreviewLayer; //Capture output layer
CAShapeLayer *layer_rect; //單純畫個白框
}
- (void)viewDidLoad
{
[super viewDidLoad];
//初始化 layout
bool_reading = NO;
[self.view setBackgroundColor:[UIColor whiteColor]];
view_back = [[UIView alloc]initWithFrame:self.view.bounds];
[view_back setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:view_back];
[view_back release];
view_fore = [[UIView alloc]initWithFrame:self.view.bounds];
[view_fore setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:view_fore];
[view_fore release];
label_value = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 320, 320)];
[label_value setBackgroundColor:[UIColor whiteColor]];
[label_value setTextColor:[UIColor blackColor]];
[label_value setLineBreakMode:NSLineBreakByWordWrapping];
[label_value setNumberOfLines:0];
[view_back addSubview:label_value];
[label_value release];
UIToolbar *toolbar_scan = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 524, 320, 44)];
[view_fore addSubview:toolbar_scan];
[toolbar_scan release];
baritem_start = [[UIBarButtonItem alloc]initWithTitle:@"start" style:UIBarButtonItemStyleBordered target:self action:@selector(buttonScan:)];
UIBarButtonItem *baritem_space = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolbar_scan setItems:@[baritem_space,baritem_start,baritem_space]];
[baritem_space release];
[baritem_start release];
}
-(IBAction)buttonScan:(id)sender{
//baritem_start Button 事件
if (!bool_reading) {
if ([self startScan]) {
[baritem_start setTitle:@"Stop"];
}
}
else{
[self stopScan];
[baritem_start setTitle:@"Start"];
}
bool_reading = !bool_reading;
}
- (BOOL)startScan {
//開始掃描
NSError *error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; //定義多媒體擷取種類為 Video
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@", [error localizedDescription]);
return NO;
}
captureSession = [[AVCaptureSession alloc] init];
[captureSession addInput:input];
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[captureSession addOutput:captureMetadataOutput];
[captureMetadataOutput release];
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("scanQueue", 0);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeQRCode,nil]];//定義辨識種類為 AVMetadataObjectTypeQRCode 若也要同時掃描其他種類條碼可在後面加入
videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
[videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[videoPreviewLayer setFrame:self.view.layer.bounds];
layer_rect = [CAShapeLayer layer];
[layer_rect setFrame:self.view.bounds];
[layer_rect setFillColor:[[UIColor clearColor] CGColor]];
[layer_rect setStrokeColor:[[UIColor whiteColor] CGColor]];
[layer_rect setLineWidth:3.0f];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 40, 280, 280)];
[layer_rect setPath:[path CGPath]];
[view_back.layer addSublayer:videoPreviewLayer];
[videoPreviewLayer release];
[view_back.layer addSublayer:layer_rect];
[captureSession startRunning];
dispatch_release(dispatchQueue);
return YES;
}
-(void)stopScan{
[captureSession stopRunning];
captureSession = nil;
[layer_rect removeFromSuperlayer];
[videoPreviewLayer removeFromSuperlayer];
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
if (metadataObjects != nil && [metadataObjects count] > 0) { //確認是否有掃到資料
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) { //確認掃描種類
dispatch_async(dispatch_get_main_queue(), ^(void){
[label_value setText:[metadataObj stringValue]];
[self stopScan];
[baritem_start setTitle:@"Start"];
});
bool_reading = NO;
}
}
}
畫面如下
以上~