二维码扫描(iOS原生二维码扫描)
一、关于二维码扫描的第三方库有很多:例如比较常用的两个
1.ZBar SDK ZBar为我们提供了两种使用方式,一种是直接调用ZBar提供的ZBarReaderViewController打开一个扫描界面,另一种方式是使用ZBar提供的可以嵌在其他视图中的ZBarReaderView,实际项目中我们更可能会使用第二种方式,这可以让我们对界面做更多的定制,详细的百度查找相关文档来看。
2.ZXing(Github镜像地址)是一个开源的条码生成和扫描库(开源协议为Apache2.0)。它不但支持众多的条码格式,而且有各种语言的实现版本,它支持的语言包括:Java、 C++、 C#、 Objective-C、ActionScript以及Ruby;首先去Google Code或Github将ZXing的代码下载下来,整个工程比较大,我们只需要其中涉及iOS的部分,所以最好做一些裁剪。简单来说,我们只需要保留cpp和iphone这2个文件夹,其余的全部删掉。
二、
1.本次介绍的是:iOS原生二维码扫描,利用iOS7自带的AVFoundation Framework 来实现二维码扫描
关于AVFoundation:AVFoundation是一个很大基础库,用来创建基于时间的视听媒体,可以使用它来检查、创建、编辑或媒体文件,也可以输入流从设备和操作视频实时捕捉和回放。详细框架介绍见官网:About AV Foundation,本文只是介绍如果使用AVFoundation获取二维码。
2.首先获取流媒体信息我们需要AVCaptureSession对象来管理输入流和输出流,AVCaptureVideoPreviewLayer对象来显示信息。
1>AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
2>AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
3>AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
4>AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现
5>AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
6>AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。
1 /* 2 步骤如下: 3 1.导入AVFoundation框架,引入<AVFoundation/AVFoundation.h> 4 2.设置一个用于显示扫描的view 5 3.实例化AVCaptureSession、AVCaptureVideoPreviewLayer 6 */ 7 8 #import "ViewController.h" 9 #import <AVFoundation/AVFoundation.h> 10 @interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate> 11 12 @property (strong,nonatomic) UIView *viewPreview ; 13 @property (strong,nonatomic) UILabel *lblStatus ; 14 @property (strong,nonatomic) UIButton *startBtn ; 15 16 @property (strong,nonatomic) UIView *boxView ; 17 @property (nonatomic) BOOL isReading ; 18 @property (strong,nonatomic) CALayer *scanLayer; 19 20 -(BOOL)startReading; 21 -(void)stopReading ; 22 23 //捕捉会话 24 @property (strong,nonatomic) AVCaptureSession *captureSession; 25 //展示layer 26 @property (strong,nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer; 27 28 @end 29 30 31 @implementation ViewController 32 33 - (void)viewDidLoad { 34 [super viewDidLoad]; 35 // self.view.backgroundColor = [UIColor whiteColor]; 36 self.captureSession = nil ; 37 _isReading = NO ; 38 [self initUI]; 39 40 41 } 42 43 -(BOOL)startReading 44 { 45 NSError *error; 46 //1.初始化捕捉设备(AVCaptureDevice),类型为AVMediaTypeVideo 47 AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 48 //2.用captureDevice创建输入流 49 AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error]; 50 if (!input) { 51 NSLog(@"%@",[error localizedDescription]); 52 return NO ; 53 } 54 //3.创建媒体数据输出流 55 AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init]; 56 // AVCaptureOutput *outPut = [[AVCaptureOutput alloc] init]; 57 //4.实例化捕捉会话 58 _captureSession = [[AVCaptureSession alloc] init]; 59 //4.1将输入流添加带会话 60 [_captureSession addInput:input]; 61 //4.2将媒体输出流添加带会话中 62 [_captureSession addOutput:captureMetadataOutput]; 63 //5.创建串行队列,并加媒体输出流添加到队列当中 64 dispatch_queue_t dispatchQueue; 65 dispatchQueue = dispatch_queue_create("myQueue", NULL); 66 //5.1.设置代理 67 // [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue]; 68 // 69 //设置代理 刷新线程 70 [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 71 //5.2.设置输出媒体数据类型为QRCode 72 // [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]]; 73 if (captureMetadataOutput) { 74 75 //设置扫码支持的编码格式 76 NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0]; 77 78 if ([captureMetadataOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode]) { 79 [array addObject:AVMetadataObjectTypeQRCode]; 80 } 81 if ([captureMetadataOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN13Code]) { 82 [array addObject:AVMetadataObjectTypeEAN13Code]; 83 } 84 if ([captureMetadataOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN8Code]) { 85 [array addObject:AVMetadataObjectTypeEAN8Code]; 86 } 87 if ([captureMetadataOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeCode128Code]) { 88 [array addObject:AVMetadataObjectTypeCode128Code]; 89 } 90 captureMetadataOutput.metadataObjectTypes = array; 91 } 92 93 //6.实例化预览图层 94 _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSessionWithNoConnection:_captureSession]; 95 //7.设置预览图层填充方式 96 [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 97 //8.设置图层的frame 98 [_videoPreviewLayer setFrame:_viewPreview.layer.bounds]; 99 //9.将图层添加到预览view的图层上 100 [_viewPreview.layer addSublayer:_videoPreviewLayer]; 101 //10.设置扫描范围 102 captureMetadataOutput.rectOfInterest = CGRectMake(0.2f, 0.2f, 0.8f, 0.8f); 103 //10.1扫描框 104 CGFloat width = _viewPreview.bounds.size.width ; 105 CGFloat height = _viewPreview.bounds.size.height; 106 self.boxView = [[UIView alloc] initWithFrame:CGRectMake(width * 0.2f, height * 0.2f, width - width * 0.4f, height - height * 0.4f)]; 107 _boxView.layer.borderColor = [[UIColor greenColor] CGColor]; 108 _boxView.layer.borderWidth = 1.0f ; 109 [_viewPreview addSubview:_boxView]; 110 //10.2扫描线 111 self.scanLayer = [[CALayer alloc] init]; 112 _scanLayer.frame = CGRectMake(0, 0, _boxView.bounds.size.width, 1); 113 _scanLayer.backgroundColor = [[UIColor brownColor] CGColor]; 114 [_boxView.layer insertSublayer:_scanLayer atIndex:0]; 115 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(moveScanLayer:) userInfo:nil repeats:YES]; 116 [timer fire]; 117 //10.开始扫描 118 [_captureSession startRunning]; 119 return YES ; 120 } 121 122 123 -(void)stopReading{ 124 [_captureSession stopRunning]; 125 _captureSession = nil; 126 [_scanLayer removeFromSuperlayer]; 127 [_videoPreviewLayer removeFromSuperlayer]; 128 } 129 130 #pragma mark --实现计时器方法moveScanLayer:(NSTimer *)timer 131 132 - (void)moveScanLayer:(NSTimer *)timer 133 { 134 CGRect frame = _scanLayer.frame; 135 if (_boxView.frame.size.height < _scanLayer.frame.origin.y) { 136 frame.origin.y = 0; 137 _scanLayer.frame = frame; 138 }else{ 139 frame.origin.y += 5; 140 [UIView animateWithDuration:0.1 animations:^{ 141 _scanLayer.frame = frame; 142 }]; 143 } 144 } 145 146 #pragma mark --初始化控件 147 -(void)initUI 148 { 149 self.viewPreview = [[UIView alloc] init]; 150 self.viewPreview.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height -200); 151 // self.viewPreview.backgroundColor = [UIColor clearColor]; 152 // self.viewPreview.alpha = 0.1f ; 153 [self.view addSubview:_viewPreview]; 154 155 self.startBtn = [UIButton buttonWithType:UIButtonTypeSystem]; 156 _startBtn.frame = CGRectMake(100, self.view.bounds.size.height - 100, 175, 30); 157 [_startBtn setTitle:@"开始" forState:UIControlStateNormal]; 158 [_startBtn addTarget:self action:@selector(startStopReading:) forControlEvents:UIControlEventTouchUpInside]; 159 [self.view addSubview:_startBtn]; 160 } 161 162 #pragma mark --实现开始和停止方法 163 -(void)startStopReading:(UIButton *)btn 164 { 165 if (!_isReading) { 166 167 if ([self startReading]) { 168 [_startBtn setTitle:@"停止" forState:UIControlStateNormal]; 169 } 170 } 171 else 172 { 173 [self stopReading]; 174 [_startBtn setTitle:@"开始" forState:UIControlStateNormal]; 175 } 176 177 _isReading = !_isReading ; 178 } 179 180 - (void)didReceiveMemoryWarning { 181 [super didReceiveMemoryWarning]; 182 // Dispose of any resources that can be recreated. 183 } 184 185 186 #pragma mark --实现AVCaptureMetadataOutputObjectsDelegate协议方法 187 -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection 188 { 189 if (metadataObjects.count > 0) { 190 AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject]; 191 NSLog(@"................%@",metadataObject.stringValue); 192 [self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO]; 193 194 } 195 } 196 197 198 - (BOOL)shouldAutorotate 199 { 200 return NO; 201 } 202 @end