iOS学习——iOS原生实现二维码扫描
最近项目上需要开发扫描二维码进行签到的功能,主要用于开会签到的场景,所以为了避免作弊,我们再开发时只采用直接扫描的方式,并且要屏蔽从相册读取图片,此外还在二维码扫描成功签到时后台会自动上传用户的当前地点,如何自动定位获取用户的当前地点在上一篇随笔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原生实现二维码扫描的更多相关文章
- iOS中 基于LBXScan库二维码扫描 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 首先声明这个二维码扫描是借助于zxing. 功能模块都完全封装好了,不过界面合你口味,直接使用就好,如果不合口味,后 ...
- iOS 简单易用的二维码扫描及生成二维码三方控件LFQRCode,可灵活自定义UI
一.扫码 扫描的控件是一个view,使用者只需贴在自己的控制器内即可.其他UI用户可在自己控制器随便添加.代码如下 - (void)viewDidLoad { [super viewDidLoad]; ...
- iOS开发-二维码扫描和应用跳转
iOS开发-二维码扫描和应用跳转 序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如Z ...
- iOS 自带二维码扫描功能的实现
自从iOS7以后中新增了二维码扫描功能.因此可以在不借助第三方类库的情况下简单的写出二维码的扫描功能: 原生的二维码扫描功能在AVFoundation框架下,所以在使用原生的二维码扫描功能时要先导入A ...
- iOS:原生二维码扫描
做iOS的二维码扫描,有两个第三方库可以选择,ZBar和ZXing.今天要介绍的是iOS7.0后AVFoundation框架提供的原生二维码扫描. 首先需要添加AVFoundation.framewo ...
- iOS原生实现二维码拉近放大
http://www.cocoachina.com/ios/20180416/23033.html 2018-04-16 15:34 编辑: yyuuzhu 分类:iOS开发 来源:程序鹅 8 300 ...
- iOS 原生二维码扫描和生成
代码地址如下:http://www.demodashi.com/demo/12551.html 一.效果预览: 功能描述:WSLNativeScanTool是在利用原生API的条件下封装的二维码扫描工 ...
- iOS 原生二维码扫描(可限制扫描区域)
篇文章的主要原因不是展示如何使用 AVFoundation 来进行二维码扫描,更主要的是限制扫描二维码的范围.(因为默认的是全屏扫描) 项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了 ...
- 【转】 iOS 原生二维码扫描(可限制扫描区域)
在用 AVFoundation 完成扫码后,遇到2个问题: 1,如何限制扫描范围? 2.条形码如何扫描? 一位朋友的文章帮助了我,特地转来,可以帮到有需要的朋友. 原文:http://blog.csd ...
随机推荐
- MySQL数据库基础
MySQL数据库基础 本文的所有操作是基于CMD环境,MySQL通过在命令行中输入SQL语句对数据库进行操作.配置问题可参考<打通MySQL的操作权限>中的内容,该文算是针对前期的环境配置 ...
- 织梦使用if判断某个字段是否为空
织梦如何使用if判断某个字段是否为空呢?我们以文章页调用文章摘要为例: 使用if语句判断摘要是否为空,如果有摘要就显示摘要模块,如果没有就不显示 {dede:field.description run ...
- com.mysql.jdbc.Driver和com.mysql.cj.jdbc.Driver的区别
概述:com.mysql.jdbc.Driver是mysql-connector-java 5中的,而com.mysql.cj.jdbc.Driver是mysql-connector-java 6中的 ...
- win10+anaconda+cuda配置dlib,使用GPU对dlib的深度学习算法进行加速(以人脸检测为例)
在计算机视觉和机器学习方向有一个特别好用但是比较低调的库,也就是dlib,与opencv相比其包含了很多最新的算法,尤其是深度学习方面的,因此很有必要学习一下.恰好最近换了一台笔记本,内含一块GTX1 ...
- JavaScript 一个进行枚举选择的jquery插件(仿easyui风格)
某次做项目要实现一个功能: 按星期选择一个连续的时间范围 比如:周一到周五,周六到周日 或 周六到周三 聪明的朋友马上想出办法:用两个选项为周一到周日的下拉列表实现,对 那样可以,但是我觉得不够友好, ...
- spring-boo hello world程序
作为一个程序猿,使用了spring好多年,现在有了spring-boot,也想尝尝鲜. 初听spring-boot,觉得很神秘,实际上就是集合了很多组件,再加上一些boot开发的启动和粘合程序. 个人 ...
- POJ - 1797 Heavy Transportation 单源最短路
思路:d(i)表示到达节点i的最大能运输的重量,转移方程d(i) = min(d(u), limit(u, i));注意优先队列应该以重量降序排序来重载小于符号. AC代码 #include < ...
- A.Alyona and copybooks
这题考查思维的全面性. 一开始我直接分类推公式,余数不同分类讨论. AC代码: #include<cstdio> #include<algorithm> using names ...
- mysql varchar vs oracle varchar2
1.错误提示: mysql的Data truncation: Data too long for column 'path' at row 1 错误原因: 1.字段过长而导致出错的, 2. 可能是因为 ...
- mac 系统安装 eclipse 方法
经过好几天的折腾,终于在各种不靠谱的经验.说明的忽悠中把自己心爱的 mac 安装上了 eclipse,看到别人的不靠谱,我决定自己写一篇经验,为了大家能够不走我这么多的弯路,也为了自己将来可以回来看看 ...