实现扫码二维码与自定义相机的功能,都要用到 AVFoundation 框架。
完成功能后发现,这俩个功能在实现上大致相同,唯一不同的地方是 设置 AVCaptureSession 的 output。
扫描二维码
self.metadataOutput = [AVCaptureMetadataOutput new];
//输出的类 为 AVCaptureMetadataOutput
[self.session addOutput:self.metadataOutput];
self.metadataOutput.metadataObjectTypes = @[
AVMetadataObjectTypeQRCode,
];
[self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
//可以通过设置 rectOfInterest 属性,来调整扫码区域。
自定义相机
self.photoOutput = [[AVCapturePhotoOutput alloc] init];
//输出的类 为 AVCapturePhotoOutput
NSDictionary *setDic = @{
AVVideoCodecKey:AVVideoCodecTypeJPEG,
};
self.photoSettings = [AVCapturePhotoSettings photoSettingsWithFormat:setDic];
[self.photoOutput setPhotoSettingsForSceneMonitoring:self.photoSettings];
[self.session addOutput:self.photoOutput];
//可以通过设置 rectOfInterest 属性,来调整扫码区域。
具体实现如下:
首先,添加如下属性
@interface XXXCaptureViewController ()<AVCaptureMetadataOutputObjectsDelegate,AVCapturePhotoCaptureDelegate>
@property (nonatomic, assign)BOOL currentAuthStatus;
@property (nonatomic, strong)AVCaptureDevice *device;
@property (nonatomic, strong)AVCaptureSession *session;
@property (nonatomic, strong)AVCaptureDeviceInput *input;
@property (nonatomic, strong)AVCaptureMetadataOutput *metadataOutput;
@property (nonatomic, strong)AVCapturePhotoOutput *photoOutput;
@property (nonatomic, strong)AVCapturePhotoSettings *photoSettings;
@property (nonatomic, strong)UIButton *takephotoButton;
在使用相机前,要查看是否授权
- (BOOL)authStatus
{
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (authStatus == AVAuthorizationStatusAuthorized)
{
return YES;
}
else
{
return NO;
}
}
如果该 App 没有授权相机功能,需要请求授权
__block typeof(self) weakSelf = self;
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted == NO)
{
weakSelf.currentAuthStatus = NO;
}
else
{
weakSelf.currentAuthStatus = YES;
[weakSelf configureCaptureSessionSettting];
}
然后添加属性的相关设置
- (void)configureCaptureSessionSettting
{
if (self.currentAuthStatus == NO)
{
return;
}
self.session = [AVCaptureSession new];
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
[self.session addInput:self.input];
//扫二维码
// [self.session addOutput:self.metadataOutput];
// self.metadataOutput.metadataObjectTypes = @[
// AVMetadataObjectTypeQRCode,//可以添加 AVMetadataObjectTypeCode39Code 等类型同时扫描条形码
// ];
// [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
//捕获照片
self.photoOutput = [[AVCapturePhotoOutput alloc] init];
NSDictionary *setDic = @{
AVVideoCodecKey:AVVideoCodecTypeJPEG,
};
self.photoSettings = [AVCapturePhotoSettings photoSettingsWithFormat:setDic];
[self.photoOutput setPhotoSettingsForSceneMonitoring:self.photoSettings];
[self.session addOutput:self.photoOutput];
AVCaptureVideoPreviewLayer* previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
dispatch_async(dispatch_get_main_queue(), ^{
[previewLayer setFrame:self.view.bounds];
[self.view.layer insertSublayer:previewLayer atIndex:0];
});
}
最后一步啦,开始捕获数据和停止补货。最好不要把它们放在主线程中使用。因为 startRunning 和 stopRunning 其实是一个 block,主线程调用可能会引起,UI卡顿。苹果官方具体解释:https://developer.apple.com/documentation/avfoundation/avcapturesession
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session startRunning];
});
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session stopRunning];
});
}