iOS 扫一扫
利用系统自带框架实现扫一扫功能
一 项目配置
扫一扫功能相机和相册权限,在info.plist中设置询问用户是否允许访问的权限。
info.plist加入NSCameraUsageDescription、NSPhotoLibraryUsageDescription、NSPhotoLibraryAddUsageDescription
	<key>NSCameraUsageDescription</key>
	<string>开启相机权限,活动扫一扫更快捷</string>
	<key>NSPhotoLibraryAddUsageDescription</key>
	<string>添加照片需要您的同意</string>
	<key>NSPhotoLibraryUsageDescription</key>
	<string>开启照片权限,美照当然要人赞!</string>
二 扫一扫权限判断
当每次进入扫一扫页面时,需要判断是否开启了权限
/** 校验是否有相机权限 */
- (void)checkCameraAuthorizationStatus:(void(^)(BOOL granted))permissionGranted
{
    AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    
    switch (videoAuthStatus) {
            // 已授权
        case AVAuthorizationStatusAuthorized:
        {
            permissionGranted(YES);
        }
            break;
            // 未询问用户是否授权
        case AVAuthorizationStatusNotDetermined:
        {
            // 提示用户授权
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                permissionGranted(granted);
            }];
        }
            break;
            // 用户拒绝授权或权限受限
        case AVAuthorizationStatusRestricted:
        case AVAuthorizationStatusDenied:
        {
            UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"请在”设置-隐私-相机”选项中,允许访问你的相机" message:nil delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
            [alert show];
            permissionGranted(NO);
        }
            break;
        default:
            break;
    }
}
三 需要用到AVCaptureDevice、AVCaptureDeviceInput、AVCaptureMetadataOutput、AVCaptureSession、AVCaptureVideoPreviewLayer
- AVCaptureDevice:捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入)
- AVCaptureDeviceInput:AVCaptureDeviceInput 代表输入设备,使用AVCaptureDevice 来初始化
- AVCaptureMetadataOutput:输出
- AVCaptureSession:session 把输入输出结合在一起,并开始启动捕获设备(摄像头)
- AVCaptureVideoPreviewLayer:图像预览层,实时显示捕获的图像
设置相机
/**
 设置相机
*/
- (void)setupCamera {
    self.avDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    self.avInput = [AVCaptureDeviceInput deviceInputWithDevice:self.avDevice error:nil];
    self.avOutput = [[AVCaptureMetadataOutput alloc]init];
    [self.avOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    self.avSession = [[AVCaptureSession alloc]init];
    [self.avSession setSessionPreset:AVCaptureSessionPresetHigh];
    if ([self.avSession canAddInput:self.avInput]){
        [self.avSession addInput:self.avInput];
    }
    if ([self.avSession canAddOutput:self.avOutput]){
        [self.avSession addOutput:self.avOutput];
    }
    
    // 二维码类型 AVMetadataObjectTypeQRCode
    if ([self.avOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode]){
        self.avOutput.metadataObjectTypes = [NSArray arrayWithObject:AVMetadataObjectTypeQRCode];
        // AVMetadataObjectTypeAztecCode 条形码
    } else{
        return ;
    }
    
    [self.avSession startRunning];//开始扫描
}
返回预览layer
/**
 显示的预览layer
 
 @return AVCaptureVideoPreviewLayer
 */
- (AVCaptureVideoPreviewLayer *)showPeviewLayer {
    self.avPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.avSession];
    self.avPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    return self.avPreviewLayer;
}
开始扫描与结束扫描
/**
 开始扫描
 */
- (void)startRunning {
    [self.avSession startRunning];
}
/**
 结束扫描
 */
- (void)stopRunning {
    [self.avSession stopRunning];
}
输出扫描结果AVCaptureMetadataOutputObjectsDelegate
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:
(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    if ([metadataObjects count] > 0){
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
        NSString *result = metadataObject.stringValue;//扫描出来的字符串
        NSLog(@"result:%@",result);
        
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"显示扫描结果" message:result delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
        [alert show];
        
        [self.avSession stopRunning];//停止扫描
    }
}
使用
	self.scanConfig = [[INQrScanConfig alloc] init];
        [self.scanConfig setupCamera];
        
        AVCaptureVideoPreviewLayer *previewLayer = [self.scanConfig showPeviewLayer];
        previewLayer.frame = self.layer.bounds;
        [self.layer insertSublayer:previewLayer atIndex:0];
        [self.scanConfig startRunning];
使用
//你要设置的矩形快的frame  为  x1, y1, w1, h1.
    //那么你的 rectOfInterest 应该设置为   (y1/h, x1/w, h1/h, w1/w)
    
    CGFloat size = 260.0;
    CGRect rect = CGRectMake((KAiSysScreenWidth - size)/2, (KAiSysScreenHeight - size)/2, size, size);
    // 使用 (y1/h, x1/w, h1/h, w1/w)
    self.avOutput.rectOfInterest = CGRectMake(rect.origin.y/KAiSysScreenHeight, rect.origin.x/KAiSysScreenWidth, size/KAiSysScreenHeight, size/KAiSysScreenWidth);
结果如图:
 

















![[QT编程系列-4]:C++图形用户界面编程,QT框架快速入门培训 - 2- QT程序的运行框架:信号、槽函数、对象之间的通信](https://img-blog.csdnimg.cn/593120b7676a468d9a242ba0fd4f4584.png)

