刚做了一个关于扫二维码的项目,以前没接触过这些,觉得很难,就网上找demo,找到了一个ZBarSDK的第三方框架,别人集成好的,感觉还是挺简单的,后来别人说有原生的而且相对还精确些,也不是很难,就在网上查阅了相关的资料,敲了一个小 demo也挺简单,总结一下的:
1.做原生的二维码扫描需添加其相应的库;
在需要调用扫描的视图导入其头文件#import <AVFoundation/AVFoundation.h>
2.主要用的类有如下几个:
AVCaptureDevice //代表抽象的硬件设备
AVCaptureDeviceInput //代表输入设备
AVCaptureMetadataOutput //表输出数据,管理着输出到一个movie或者图像
AVCaptureSession //它是input和output的桥梁。它协调着intput到output的数据传输
AVCaptureVideoPreviewLayer //供用户扫描可见的层
在 .h文件中声明它
@property (strong, nonatomic) AVCaptureDevice *device; //代表抽象的硬件设备
@property (strong, nonatomic) AVCaptureDeviceInput *input; //代表输入设备
@property (strong, nonatomic) AVCaptureMetadataOutput *output; //表输出数据,管理着输出到一个movie或者图像
@property (strong, nonatomic) AVCaptureSession *session; //它是input和output的桥梁。它协调着intput到output的数据传输
@property (strong, nonatomic)AVCaptureVideoPreviewLayer *preview; //供用户扫描可见的层
@property (nonatomic, strong) CALayer *calayer; //扫描线的层
@property (nonatomic, strong) NSTimer *timer; //定时器
@property (nonatomic, strong) UIView *boxView; //扫描框
3.实现如下:
a.定义两个成员变量:控制扫描线
BOOL upOrdown; //bool判断扫描线上下移动
NSInteger num; //位移
b.二维码扫描的核心代码
-(void)initCapture{
// 1. 摄像头设备
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 2. 设置输入
// 因为模拟器是没有摄像头的,因此在此最好做一个判断
NSError *error;
_input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
if (error) {
NSLog(@"没有摄像头-%@", error.localizedDescription);
return;
}
// 3. 设置输出(Metadata元数据)
_output = [[AVCaptureMetadataOutput alloc] init];
// 3.1 设置输出的代理
// 说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 4. 拍摄会话
_session = [[AVCaptureSession alloc] init];
[_session setSessionPreset:AVCaptureSessionPresetHigh];
// 添加session的输入和输出
if ([_session canAddInput:self.input]) {
[_session addInput:self.input];
}
if ([_session canAddOutput:self.output]) {
[_session addOutput:self.output];
}
// 4.1 设置输出的格式
// 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
_output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
// 5. 设置预览图层(用来让用户能够看到扫描情况)
_preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
// 5.1 设置preview图层的属性
_preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
// 5.3 将图层添加到视图的图层
_preview.frame = self.view.layer.bounds;
[self.view.layer insertSublayer:_preview atIndex:0];
//7.添加扫描框
_boxView = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-220)/2.0,124,220,220)];
_boxView.backgroundColor = [UIColor clearColor];
_boxView.layer.borderColor = [UIColor greenColor].CGColor;
_boxView.layer.borderWidth = 1.0f;
[self.view addSubview:_boxView];
//8.设置扫描区域
[_output setRectOfInterest:CGRectMake(124/SCREEN_HEIGHT,((SCREEN_WIDTH-220)/2)/SCREEN_WIDTH,220/SCREEN_HEIGHT,220/SCREEN_WIDTH)];
//9.0 添加扫描框里面的扫描线
_calayer = [CALayer layer];
[_calayer setFrame:CGRectMake(0, 10, CGRectGetWidth(_boxView.frame), 1)];
_calayer.backgroundColor = [UIColor brownColor].CGColor;
[_boxView.layer addSublayer:_calayer];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(animationEvent) userInfo:nil repeats:YES];
//9.1设置扫描区域顶部透明图层
UIView *topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH,_boxView.frame.origin.y)];
topView.backgroundColor = [UIColor blackColor];
topView.alpha = 0.4;
[self.view addSubview:topView];
//9.2设置扫描区域底部透明图层
UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_boxView.frame), SCREEN_WIDTH, SCREEN_HEIGHT-CGRectGetMaxY(_boxView.frame))];
bottomView.backgroundColor = [UIColor blackColor];
bottomView.alpha = 0.4;
[self.view addSubview:bottomView];
//9.3设置扫描区域左部透明图层
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, _boxView.frame.origin.y, _boxView.frame.origin.x, CGRectGetHeight(_boxView.frame))];
leftView.backgroundColor = [UIColor blackColor];
leftView.alpha = 0.4;
[self.view addSubview:leftView];
//9.4设置扫描区域右部透明图层
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(_boxView.frame), _boxView.frame.origin.y, SCREEN_WIDTH-CGRectGetMaxX(_boxView.frame),CGRectGetHeight(_boxView.frame))];
rightView.backgroundColor = [UIColor blackColor];
rightView.alpha = 0.4;
[self.view addSubview:rightView];
// 10. 启动会话
[_session startRunning];
}
c.成功后进入其代理方法
#pragma mark AVCaptureMetadataOutputObjectsDelegate
// 此方法是在识别到QRCode,并且完成转换
// 如果QRCode的内容越大,转换需要的时间就越长
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
// 会频繁的扫描,调用代理方法
// 1. 如果扫描完成,停止会话
NSString *stringValue;
[_session stopRunning];
if ([metadataObjects count] > 0) {
AudioServicesPlaySystemSound (1002); //2.扫描成功后发出声音
AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
// 提示:如果需要对url或者名片等信息进行扫描,可以在此进行扩展!
stringValue = metadataObject.stringValue;
NSLog(@"infomation is %@",stringValue);
}
//销毁定时器
[_timer invalidate];
// 4. 删除预览图层
[self.preview removeFromSuperlayer];
}
d.控制扫描线上下扫描代码:
//扫描线上下移动
-(void)animationEvent{
CGFloat height = CGRectGetHeight(_boxView.frame);
if (upOrdown == NO) {
num ++;
_calayer.frame = CGRectMake(0, 10 + num, CGRectGetWidth(_boxView.frame), 1);
if (num == height) {
upOrdown = YES;
}
}
else {
num --;
_calayer.frame = CGRectMake(0, num - 10, CGRectGetWidth(_boxView.frame), 1);
if (num == 0) {
upOrdown = NO;
}
}
}