最近项目上需要开发扫描二维码进行签到的功能,主要用于开会签到的场景,所以为了避免作弊,我们再开发时只采用直接扫描的方式,并且要屏蔽从相册读取图片,此外还在二维码扫描成功签到时后台会自动上传用户的当前地点,如何自动定位获取用户的当前地点在上一篇随笔iOS学习——自动定位中已经讲过了,本文就简单地说一下如何利用iOS原生的模块实现二维码的扫描。

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

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

@interface CJScanQRCodeViewController () <AVCaptureMetadataOutputObjectsDelegate>

@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

  首先,我们是需要进行对我们的一些设备进行配置,比喻需要用到自动定位,就需要对定位信息进行配置,接着对二维码扫描的相关设备进行配置,然后对我们的缩放手势进行设置,都配置完之后,直接开始启动二维码扫描就可以了,成功扫码并识别到信息时候会调用对应的 AVCaptureMetadataOutputObjectsDelegate 代理的 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection 方法进行后期处理,我们需要实现代理的该方法,在其中编写我们需要的功能逻辑。

- (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)/(*ZYAppWidth), (viewH-scanViewH)/(*viewH), scanViewH/ZYAppWidth, scanViewH/viewH)];
//预览层 初始化,self.session负责驱动input进行信息的采集,layer负责把图像渲染显示
//预览层的区域设置为整个屏幕,这样可以方便我们进行移动二维码到扫描区域,在上面我们已经对我们的扫描区域进行了相应的设置
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
self.previewLayer.frame = CGRectMake(, , 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(, (viewH+scanViewH)/+10.0f, ZYAppWidth, 20.0f)];
label.text = @"扫一扫功能仅用于会议签到";
label.font = FONT(15.0f);
label.textColor = [UIColor whiteColor];
label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:label];
}

  接下来我们看一下如何配置我们的缩放手势,这个相对而言就很简单了,我们直接在self.view上添加一个缩放手势,并在对应的方法中对我们的相机设备的焦距进行修改就达到了缩放的目的。

- (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] >= ) {
//数组中包含的都是AVMetadataMachineReadableCodeObject 类型的对象,该对象中包含解码后的数据
AVMetadataMachineReadableCodeObject *qrObject = [metadataObjects lastObject];
//拿到扫描内容在这里进行个性化处理
NSString *result = qrObject.stringValue;
//解析数据进行处理并实现相应的逻辑
//代码省略
}

iOS学习——iOS原生实现二维码扫描的更多相关文章

  1. iOS中 基于LBXScan库二维码扫描 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 首先声明这个二维码扫描是借助于zxing. 功能模块都完全封装好了,不过界面合你口味,直接使用就好,如果不合口味,后 ...

  2. iOS 简单易用的二维码扫描及生成二维码三方控件LFQRCode,可灵活自定义UI

    一.扫码 扫描的控件是一个view,使用者只需贴在自己的控制器内即可.其他UI用户可在自己控制器随便添加.代码如下 - (void)viewDidLoad { [super viewDidLoad]; ...

  3. iOS开发-二维码扫描和应用跳转

    iOS开发-二维码扫描和应用跳转   序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如Z ...

  4. iOS 自带二维码扫描功能的实现

    自从iOS7以后中新增了二维码扫描功能.因此可以在不借助第三方类库的情况下简单的写出二维码的扫描功能: 原生的二维码扫描功能在AVFoundation框架下,所以在使用原生的二维码扫描功能时要先导入A ...

  5. iOS:原生二维码扫描

    做iOS的二维码扫描,有两个第三方库可以选择,ZBar和ZXing.今天要介绍的是iOS7.0后AVFoundation框架提供的原生二维码扫描. 首先需要添加AVFoundation.framewo ...

  6. iOS原生实现二维码拉近放大

    http://www.cocoachina.com/ios/20180416/23033.html 2018-04-16 15:34 编辑: yyuuzhu 分类:iOS开发 来源:程序鹅 8 300 ...

  7. iOS 原生二维码扫描和生成

    代码地址如下:http://www.demodashi.com/demo/12551.html 一.效果预览: 功能描述:WSLNativeScanTool是在利用原生API的条件下封装的二维码扫描工 ...

  8. iOS 原生二维码扫描(可限制扫描区域)

    篇文章的主要原因不是展示如何使用  AVFoundation 来进行二维码扫描,更主要的是限制扫描二维码的范围.(因为默认的是全屏扫描) 项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了 ...

  9. 【转】 iOS 原生二维码扫描(可限制扫描区域)

    在用 AVFoundation 完成扫码后,遇到2个问题: 1,如何限制扫描范围? 2.条形码如何扫描? 一位朋友的文章帮助了我,特地转来,可以帮到有需要的朋友. 原文:http://blog.csd ...

随机推荐

  1. PHP 批量获取指定目录下的文件列表(递归,穿透所有子目录)

    //调用 $dir = '/Users/xxx/www'; $exceptFolders = array('view','test'); $exceptFiles = array('BaseContr ...

  2. FFT模板(多项式乘法)

    FFT模板(多项式乘法) 标签: FFT 扯淡 一晚上都用来捣鼓这个东西了...... 这里贴一位神犇的博客,我认为讲的比较清楚了.(刚好适合我这种复数都没学的) http://blog.csdn.n ...

  3. Python 运算符,你了解多少?

    新年新气象,文档更新继续~ 一.什么是运算符? 之前我们有定义过变量,变量是用来存储数据的,存储的数据是为了运算,运算就会使用到运算符 举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为 ...

  4. Linux 6.4 设置yum 为centOS源

    一. 删除Redhat 自带的yum // root 用户执行 rpm -aq|grep yum|xargs rpm -e --nodeps 二 .下载CentOS 的 yum 安装文件 wget h ...

  5. 将Tomcat配置到你的mac电脑上,命令行启动tomcat

    1.下载tomcat7文件 2.编辑打开.bash_profile vim .bash_profile 3.在该文件最后面添加(CATALINA_HOME为tomcat解压目录) CATALINA_H ...

  6. 【前端开发】解决ios设备上fixed浮动的input输入框兼容问题

    我们在开发移动端页面时,经常会存在这种需求,在页面顶部或底部有一个输入框,一直浮动在顶部或底部位置,中间部分的内容是可以滚动的.比如底部输入框的搜索功能,或底部输入框的写评论功能. 这种问题,我们一般 ...

  7. WAMP环境搭建过程中遇到的种种问题

    1,可以选择已经打包好的继承安装包,通常包含apache,mysql,PHP,phpMyadmin.如appserv和wamp. 2,自己分别安装. 第一步:安装mysql,注意设置root对应的密码 ...

  8. Duilib第一步(III)-知识进阶

    核心模块 CWindowWnd:窗口对象管理父类 创建窗口. 窗口消息过程处理. 提供窗口子类化.超类化接口. CDialogBuilder:空间布局类 解析XML界面布局文件,构建控件树 创建控件对 ...

  9. css的一些复习

    css,全称Cascading Style Sheets,层叠样式表. css选择器是从右往左解析的,解析速度会比较快. 选择器 选择器权重 !important 优先级最高 元素属性 优先级高 相同 ...

  10. CodeForces - 727E Games on a CD 字符串Hash

    题意:有n个单词,每个单词长度为k,顺时针将它们写成一个圆圈串.现在知道g个长度为k的单词,是否可以从这g个单词中选择n个形成这个圆圈串?如果有多个答案,任意输出一个. 思路 可以发现,如果枚举第一个 ...