iOS 7 之前一直都是使用第三方的框架实现二维码扫描,比如ZBar和ZXing。感兴趣的可以去搜这两个开源的库用用。不过iOS 7 之后苹果出了相应的原生API处理二维码的扫描。效率上感觉原生的还是要好一点,应用中使用的时候,扫描一维码还是比较费劲,不知道微信的条形码扫描是用什么做的,扫描挺快的。
首先借一张图了解一下AVFoundation框架
AVFoundation 是一个很大基础库,用它来处理媒体相关的操作。本文只是用它实现二维码扫描,想了解更多功能,请查阅官网API。实现二维码扫描需要使用的类及其子类
- AVCaptureDevice 代表了输入设备,例如摄像头与麦克风
- AVCaptureInput 代表了输入数据源
AVCaptureDeviceInput
是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。- AVCaptureOutput 代表了输出数据源
AVCaptureMetadataOutput
是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现- AVCaptureSession 用于协调输入与输出之间的数据流
使用demo。TP
- 创建AVCaptureSession对象,首先导入头文件#import <AVFoundation/AVFoundation.h>
//新建session AVCaptureSession *session = [[AVCaptureSession alloc] init]; self.session = session;
2. 创建一个AVCaptureDevice代表代表输入设备。在这里我们制定设备用于摄像
//新建device Type是一个枚举:AVMediaTypeAudio,AVMediaTypeVideo,AVMediaTypeMetadata AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
3. 创建AVCaptureDeviceInput,并添加到Session中,我们需要使用AVCaptureDeviceInput来让设备添加到session中, AVCaptureDeviceInput负责管理设备端口。我们可以理解它为设备的抽象。一个设备可能可以同时提供视频和音频的捕捉。我们可以分别用AVCaptureDeviceInput来代表视频输入和音频输入。
//新建output并添加到session AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init]; dispatch_queue_t dispathcQueue; dispathcQueue = dispatch_queue_create("myQueue", nil); [output setMetadataObjectsDelegate:self queue:dispathcQueue]; [session addOutput:output]; //这里注意要把这代码写在,output添加到session后,否则会闪退。 [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
4. 新建AVCaptureVideoPreviewLayer,显示output的内容
AVCaptureVideoPreviewLayer *viewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:session]; viewLayer.frame = self.view.bounds; [self.view.layer addSublayer:viewLayer]; [session startRunning];
demo很简单,不想手写代码的同学可以到gitHub上下载代码 TP
项目中往往要比demo要求的多,实际项目中遇到的问题,在这给大家分享一下,希望对遇到同样问题的人能有所帮助,如果你有更好的解决方案@me。
1. 实现微信里扫描时,二维码图片显示的比较大。
我的解决方案是,对viewLayer进行放大
self.Videolayer.transform = CATransform3DMakeScale(2, 2, 1);//图像放大
2. 扫描时需要指定扫描的区域
output类有个属性rectOfInterest可以设置扫描的区域,这里有个坑,这个区域的原点是右上角,并且width 和 height也是和正常的反过来。值是0-1之间的小数,是占屏幕的百分比。
3. 如果应用在使用相机时被用户拒绝,可以获得当前的状态,并提示用户
//隐私里设置 AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];