iOS原生实现二维码扫描

二维码扫描是很多应用都会实现的功能,比较著名的第三方开源库是Google出品的ZXing,其的OC的移植版本是ZXingObjc。iOS系统原生的二维码扫描模块是在iOS7之后推出的,它主要是利用iOS设备的后置摄像头进行实现的。

要调用系统的摄像头识别二维码,我们需要导入系统的AVFoundation库。使用系统的摄像头,我们一般的需要以下五个对象:一个后置摄像头设备(AVCaptureDevice)、一个输入(AVCaptureDeviceInput)、一个输出(AVCaptureMetadataOutput)、一个协调控制器(AVCaptureSession)、一个预览层(AVCaptureVideoPreviewLayer),此外为了更好的体验效果,我们加入了缩放手势,在进行二维码扫描的时候可以手动进行缩放扫描区域,以获得更好的扫描效果。

.h文件

@interface CJScanQRCodeViewController () 
@property (strong, nonatomic) AVCaptureDevice * device; //捕获设备,默认后置摄像头
@property (strong, nonatomic) AVCaptureDeviceInput * input; //输入设备@property (strong, nonatomic) AVCaptureMetadataOutput * output;//输出设备,需要指定他的输出类型及扫描范围
@property (strong, nonatomic) AVCaptureSession * session; //AVFoundation框架捕获类的中心枢纽,协调输入输出设备以获得数据
@property (strong, nonatomic) AVCaptureVideoPreviewLayer * previewLayer;//展示捕获图像的图层,是CALayer的子类
@property (strong, nonatomic) UIPinchGestureRecognizer *pinchGes;//缩放手势@property (assign, nonatomic) CGFloat scanRegion_W;//二维码正方形扫描区域的宽度,根据不同机型适配
@end

.m文件

- (void)viewDidLoad {
    [super viewDidLoad];    //页面标题
    self.title = @"扫一扫";    //配置定位信息    [self configLocation];    //配置二维码扫描    [self configBasicDevice];    //配置缩放手势    [self configPinchGes];    //开始启动    [self.session startRunning];
}
​五大设备的初始化:
- (void)configBasicDevice{    //默认使用后置摄像头进行扫描,使用AVMediaTypeVideo表示视频 self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];    //设备输入 初始化 self.input = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:nil];    //设备输出 初始化,并设置代理和回调,当设备扫描到数据时通过该代理输出队列,一般输出队列都设置为主队列,也是设置了回调方法执行所在的队列环境 self.output = [[AVCaptureMetadataOutput alloc]init];    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];    //会话 初始化,通过 会话 连接设备的 输入 输出,并设置采样质量为 高 self.session = [[AVCaptureSession alloc]init];    [self.session setSessionPreset:AVCaptureSessionPresetHigh];    //会话添加设备的 输入 输出,建立连接 if ([self.session canAddInput:self.input]) {        [self.session addInput:self.input];    }    if ([self.session canAddOutput:self.output]) {        [self.session addOutput:self.output];    }    //指定设备的识别类型 这里只指定二维码识别这一种类型 AVMetadataObjectTypeQRCode    //指定识别类型这一步一定要在输出添加到会话之后,否则设备的课识别类型会为空,程序会出现崩溃    [self.output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];    //设置扫描信息的识别区域,本文设置正中央的一块正方形区域,该区域宽度是scanRegion_W    //这里考虑了导航栏的高度,所以计算有点麻烦,识别区域越小识别效率越高,所以不设置整个屏幕 CGFloat navH = self.navigationController.navigationBar.bounds.size.height;    CGFloat viewH = ZYAppHeight - navH;    CGFloat scanViewH = self.scanRegion_W;    [self.output setRectOfInterest:CGRectMake((ZYAppWidth-scanViewH)/(2*ZYAppWidth), (viewH-scanViewH)/(2*viewH), scanViewH/ZYAppWidth, scanViewH/viewH)];    //预览层 初始化,self.session负责驱动input进行信息的采集,layer负责把图像渲染显示    //预览层的区域设置为整个屏幕,这样可以方便我们进行移动二维码到扫描区域,在上面我们已经对我们的扫描区域进行了相应的设置 self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];    self.previewLayer.frame = CGRectMake(0, 0, ZYAppWidth, ZYAppHeight);    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;    [self.view.layer addSublayer:self.previewLayer];    //扫描框 和扫描线的布局和设置,模拟正在扫描的过程,这一块加不加不影响我们的效果,只是起一个直观的作用 TNWCameraScanView *clearView = [[TNWCameraScanView alloc]initWithFrame:self.view.frame navH:navH];    [self.view addSubview:clearView];    //扫描框下面的信息label布局 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, (viewH+scanViewH)/2+10.0f, ZYAppWidth, 20.0f)];    label.text = @"扫一扫功能仅用于会议签到";    label.font = FONT(15.0f);    label.textColor = [UIColor whiteColor];    label.textAlignment = NSTextAlignmentCenter;    [self.view addSubview:label]; }

缩放手势:

- (void)configPinchGes{
    self.pinchGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchDetected:)];
    [self.view addGestureRecognizer:self.pinchGes];
}- (void)pinchDetected:(UIPinchGestureRecognizer*)recogniser{    if (!_device){        return;
    }   //对手势的状态进行判断
    if (recogniser.state == UIGestureRecognizerStateBegan){
        _initScale = _device.videoZoomFactor;
    }    //相机设备在改变某些参数前必须先锁定,直到改变结束才能解锁
    NSError *error = nil;
    [_device lockForConfiguration:&error]; //锁定相机设备
    if (!error) {
        CGFloat zoomFactor; //缩放因子
        CGFloat scale = recogniser.scale;        if (scale < 1.0f) {
            zoomFactor = self.initScale - pow(self.device.activeFormat.videoMaxZoomFactor, 1.0f - recogniser.scale);
        } else {
            zoomFactor = self.initScale + pow(self.device.activeFormat.videoMaxZoomFactor, (recogniser.scale - 1.0f) / 2.0f);
        }
        zoomFactor = MIN(15.0f, zoomFactor);
        zoomFactor = MAX(1.0f, zoomFactor);
        _device.videoZoomFactor = zoomFactor;
        [_device unlockForConfiguration];
    }
} 

代理的回调方法:

#pragma mark - AVCaptureMetadataOutputObjectsDelegate//后置摄像头扫描到二维码的信息- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    [self.session stopRunning];   //停止扫描
    if ([metadataObjects count] >= 1) {        //数组中包含的都是AVMetadataMachineReadableCodeObject 类型的对象,该对象中包含解码后的数据
        AVMetadataMachineReadableCodeObject *qrObject = [metadataObjects lastObject];        //拿到扫描内容在这里进行个性化处理
        NSString *result = qrObject.stringValue;        //解析数据进行处理并实现相应的逻辑        //代码省略}
有疑问咨询QQ:1147726728

你可能感兴趣的:(iOS,Xcode,Object-c,i)