实现扫码二维码的功能,需要使用到 AVFoundation 框架。
1、在简述代码前,首先了解一下一下几个需要用到的属性:
AVCaptureDevice
一个AVCaptureDevice代表一个物理设备,它提供一个实时的输入媒体数据,例如:视频,音频;
每个AVCaptureDevice实例对象都代表着一个设备,如:相机,麦克风;一个AVCaptureDevice实例对象不能被直接创建,可以通过AVCaptureDeviceDiscoverySession获取当前所有可使用的设备;设备可以提供一个或者多个给定的的媒体类型的流;应用程序可以搜索获取设备通过使用AVCaptureDeviceDiscoverySession匹配所需的标准,或可能获得一个引用默认设备通过使用匹配所需的标准通过+[AVCaptureDevice defaultDeviceWithDeviceType:mediaType:position:
AVCaptureSession
AVCaptureSession是AVFoundation的核心类,用于捕捉视频和音频,协调视频和音频的输入和输出流;
执行实时捕获,一个客户可以实例化AVCaptureSession并添加适当AVCaptureInputs,如AVCaptureDeviceInput和输出,如AVCaptureMovieFileOutput。[AVCaptureSession startRunning]启动从输入到输出的数据流,[AVCaptureSession stopRunning]停止流。客户端可以设置sessionPreset属性来定制输出的质量级别或比特率。
AVCaptureDeviceInput
AVCaptureInput它是一个抽象类,提供一个实例对象将捕获到的输入源链接到AVCaptureSession上。既然是抽象类我们显然是无法直接使用的,所以我们只能用其子类AVCaptureDeviceInput、AVCaptureScreenInput和AVCaptureMetadataInput来创建;
-
AVCaptureDeviceInput:使用该对象从AVCaptureDevice设备获取媒体数据,该对象将会被添加给AVCaptureSession管理。
-
AVCaptureScreenInput:使用该对象从屏幕获取数据(用于录制屏幕).该对象将会被添加给AVCaptureSeesion管理。
-
AVCaptureMetaDataInput:获取元数据(很少使用).
AVCaptureMetadataOutput
AVCaptureOutput:相对应于AVCaptureInput,它也是一个抽象类,用来接收各种输出数据,为AVCaptureSession提供一个输出目标接口。所以我们还是只能使用其子类
AVCaptureStillImageOutput //使用AVCapturePhotoOutput替代了
AVCaptureVideoDataOutput //可以用来处理被捕获的视频中未压缩或压缩的帧。
AVCaptureAudioDataOutput //可以用来处理从音频捕获的未压缩或压缩的样本
AVCaptureMetadataOutput //可以用来处理附加连接中的元数据对象
AVCaptureFileOutput //文件输出可以开始记录到一个新的文件使用startRecordingToOutputFileURL:recordingDelegate:方法
AVCapturePhotoOutput //它支持照片捕捉生活,preview-sized图像传递,广泛的颜色,原生,原生+JPG和 原生+ DNG格式
AVCaptureVideoPreviewLayer
AVCaptureVideoPreviewLayer视频预览层,其实可以把它想象成一个画布,我们通过摄像头拍摄到的画面就显示在这个画布上。AVCaptureVideoPreviewLayer所呈现的画面是连续的,并非单张的静态影像,当然你也可以略过设定 AVCaptureVideoPreviewLayer 的步骤,不显示摄影机所拍摄到的画面,这并不会有任何影响。它是CALayer的子类,它可以实时查看拍照或视频录制效果,需要指定对应的 AVCaptureSession对象;
2、项目中需要用到的相机权限
由于扫描二维码需要使用摄像头,所以在项目中的info.plist文件中的key写入Privacy - Camera Usage Description,value中写入你需要用到的文字描述,如下图所示
3、实现方法
在使用相机前要先查看相机是否授权
#pragma makr - 请求权限
- (BOOL)requestDeviceAuthorization{
AVAuthorizationStatus deviceStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (deviceStatus == AVAuthorizationStatusRestricted ||
deviceStatus == AVAuthorizationStatusDenied){
NSLog(@"相机未授权");
return NO;
}
NSLog(@"相机已授权");
return YES;
}
未授权直接return,已授权则继续操作
- (void)startCapture {
if (![self requestDeviceAuthorization]) {
NSLog(@"没有访问相机权限!");
return;
}
// [self.session beginConfiguration];
//添加设备输入流到会话对象
if ([self.session canAddInput:self.input]) {
[self.session addInput:self.input];
}
//设置数据输出类型,需要将数据输出添加到会话后,才能指定元数据类型,否则会报错
if ([self.session canAddOutput:self.metadataOutput]) {
[self.session addOutput:self.metadataOutput];
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
NSArray *types = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode93Code];
self.metadataOutput.metadataObjectTypes = types;
}
[self.session commitConfiguration];
/*开始捕获数据和停止捕获。最好不要把它们放在主线程中使用。因为 startRunning 和 stopRunning 其实是一个 block,主线程调用可能会引起,UI卡顿。*/
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session startRunning];
});
}
废话不多说,直接上代码ZWScan。