iOS开发-二维码扫描和应用跳转
iOS开发-二维码扫描和应用跳转
序言
前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢?
在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar。使用时集成麻烦,出错也不方便调试。在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架。本文讲解如何使用原生框架实现二维码扫描功能,并且进行扫描后的项目跳转。
ps:本期的源代码会在文章结尾给出链接
扫描相关类
二维码扫描需要获取摄像头并读取照片信息,因此我们需要导入系统的AVFoundation框架,创建视频会话。我们需要用到一下几个类:
- AVCaptureSession 会话对象。此类作为硬件设备输入输出信息的桥梁,承担实时获取设备数据的责任
- AVCaptureDeviceInput 设备输入类。这个类用来表示输入数据的硬件设备,配置抽象设备的port
- AVCaptureMetadataOutput 输出类。这个支持二维码、条形码等图像数据的识别
- AVCaptureVideoPreviewLayer 图层类。用来快速呈现摄像头获取的原始数据
二维码扫描功能的实现步骤是创建好会话对象,用来获取从硬件设备输入的数据,并实时显示在界面上。在扫描到相应图像数据的时候,通过AVCaptureVideoPreviewLayer类型进行返回
应用跳转
在使用第三方登陆、分享sdk的时候,我们的项目会在本机安装有目标平台的应用的情况下进行应用跳转,并且传递信息过去。这在沙盒机制下的iOS应用而言,理应是不符合规则的。但是,iOS SDK给我们提供了一个叫做url scheme的机制来实现这个功能。
url scheme让我们可以像使用Safari打开网页的方式跳转到其他应用中,并使用类似网络请求的GET请求的参数拼凑方式来在不同应用之间传递数据。
使用url scheme的第一步是在项目的info.plist文件中添加新row,命名为URL types
展开新增的字典,我们修改其中的URL Identifier以及新增加一个字段
URL Schemes。
Identifier用来跳转后,让跳转应用识别从哪里跳转过来的,我们可以设置为bundleID反转,来确保其特殊性。
URL Schemes是一个数组,我们将在这个数组里面自定义自己的url schemes,这里我们填写应用名。最终效果如下:
接着,我们就可以在其他应用中通过openURL:方法打开我们的app。
二维码扫描
二维码扫描的步骤:
1、创建设备会话对象,用来设置设备数据输入
2、获取摄像头,并且将摄像头对象加入当前会话中
3、实时获取摄像头原始数据显示在屏幕上
4、扫描到二维码/条形码数据,通过协议方法回调
会话对象
AVCaptureSession
的创建_session = [AVCaptureSession new];
[_session setSessionPreset: AVCaptureSessionPresetHigh]; //高质量采集
[self setupIODevice];setupIODevice
方法中懒加载方式创建输入对象和输出对象,注意必须在输出数据对象加入到当前会话后才能设置识别的数据格式。这里设置为扫描二维码以及条形码[_session addInput: self.input];
[_session addOutput: self.output];
_output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];创建
AVCaptureMetadataOutput
设置好扫描成功回调代理以及回调线程_output = [AVCaptureMetadataOutput new];
[_output setMetadataObjectsDelegate: self queue: dispatch_get_main_queue()];创建
AVCaptureDeviceInput
输入设备为手机摄像头AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
_input = [AVCaptureDeviceInput deviceInputWithDevice: device error: nil];创建
AVCaptureVideoPreviewLayer
对象来实时获取摄像头图像,我们需要调用[self.view addSubview: self.scanView]
把摄像头获取的图像实时展示在屏幕上_scanView = [AVCaptureVideoPreviewLayer layerWithSession: self.session];
_scanView.videoGravity = AVLayerVideoGravityResizeAspectFill;
_scanView.frame = self.bounds;实现
captureOutput: didOutputMetadataObjects: fromConnection:
来获取扫描得到的数据。回调参数metadataObjects中存放了扫描结果,我们需要先判断这个数组的数据个数不为0再执行下面的代码:[self stop];
AVMetadataMachineReadableCodeObject * metadataObject = metadataObjects[0];
if ([self.delegate respondsToSelector: @selector(scanView:codeInfo:)]) {
[self.delegate scanView: self codeInfo: metadataObject.stringValue];
[self removeFromSuperview];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName: LXDSuccessScanQRCodeNotification object: self userInfo: @{ LXDScanQRCodeMessageKey: metadataObject.stringValue }];
读取二维码信息进行应用跳转
首先要说明的是,二维码并非一定要存储应用的url scheme。例如公众号的二维码,虽然不知道是怎样的数据存储,但肯定不是应用跳转。可以给自己的应用指定一个二维码数据规则,例如支付宝付款扫描是读取商品的ID、价格等信息,然后进行页面跳转付款。
这里我们使用上面设置的url scheme,我们通过制作二维码方法来定制一个存储应用跳转信息的二维码,通过下面的代理创建一个存储url scheme(使用url scheme的时候要注意在后面加上://后才能使用openURL进行跳转)的二维码,这一步应该放到模拟器上面生成
- (IBAction)createBarcode:(id)sender
{
UIImage image = [UIImage imageOfQRFromURL: @"LXDDrawLosts://" codeSize: 160.f red: 123 green: 189 blue: 229 insertImage: nil];
CGSize size = image.size;
UIImageView imageView = [[UIImageView alloc] initWithFrame: ((CGRect){(CGPointZero), (size)})];
imageView.center = self.view.center;
imageView.image = image;
[self.view addSubview: imageView];
}
创建二维码扫描控制器,然后对我们生成的二维码进行扫描(这一步要在真机上面完成,上面url scheme的应用应当通过xcode安装在手机上,才能完成跳转)
LXDScanCodeController * scanCodeController = [LXDScanCodeController scanCodeController];
scanCodeController.scanDelegate = self;
[self.navigationController pushViewController: scanCodeController animated: YES];
扫描成功后判断是否可以打开跳转,如果你的应用有一套二维码数据存储的规则,那么在不能跳转的时候应该按照这套规则解析数据。这里我直接在无法跳转的情况下显示警告框告诉用户无法解析二维码:
NSURL * url = [NSURL URLWithString: codeInfo];
if ([[UIApplication sharedApplication] canOpenURL: url]) {
[[UIApplication sharedApplication] openURL: url];
} else {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle: @"警告" message: [NSString stringWithFormat: @"%@:%@", @"无法解析的二维码", codeInfo] delegate: nil cancelButtonTitle: @"确定" otherButtonTitles: nil];
[alertView show];
}
按照上面的步骤进行的话,那么在你扫完二维码之后,你的手机就会跳转到刚才设置url scheme的应用中。
扫描优化
上面已经完成了二维码的扫描功能实现,但是现在你会发现我们在使用上面代码进行扫描的时候,整个屏幕都是扫描范围,这样会影响扫描的准确性以及我们调整扫描范围的难度。
苹果提供了一种方式让我们规定扫描范围:在AVCaptureMetadataOutput
中有一个叫做rectOfInterest
的CGRect类型属性,这个属性用来限制扫描范围。
这个属性的每一个值取值范围在0~1之间,代表的是对应轴上的比例大小。最开始我以为这个是以左上角为原点,后来设置为CGRectMake(0.3, 0.35, 0.4, 0.3)
发现和预期的不一样,因为这个属性是以屏幕右上角为坐标原点,并且宽高的顺序要对换过来
如图所示,由于坐标系的不同,原本CGRectMake(0.3, 0.35, 0.4, 0.3)
到了新坐标系中就变成了CGRectMake(0.35, 0.3, 0.3, 0.4)
。那么大家设置成新的扫描范围之后,重新运行扫描程序,看看效果——然而,我们发现并不能扫描成功,这是因为这个扫描区域不仅仅是坐标系原点发生了改变。如下图所示
按照上面CGRect的设置,我是想要把扫描范围控制在屏幕x轴上面0.3-0.7,y轴上0.35-0.65之间的范围。但是在这个属性中,width和height分别表示的是在rectOfInterest坐标中扫描矩形右下角的坐标点位置。因此,这个扫描范围应该是CGRectMake(0.35, 0.3, 0.65, 0.7)
。除了设置好扫描范围之内,我们还可以仿照微信的扫描,给非扫描范围加上一层半透明的黑色layer
应用传值
前面说过,url scheme不仅仅支持应用跳转,它还支持使用类似get请求的方式在应用间传值。上面跳转的url scheme是LXDDrawLosts://
,那么类似get请求,我们在这个字符串后面加上一个?
表示区分开参数和应用id,使用&
分隔不同参数,然后后面按照字段名=属性值
的方式拼凑链接。
比如,假设这是一个即时通讯app,那么我可以制定这样的一个跳转参数规则:
method
表示操作类型userId
用户idtitle
分享标题message
分享消息link_url
分享链接
那么,如果传入的是LXDDrawLosts://?method=addFriends&userId=10086
这可能代表的是扫描后添加id为10086的新好友。
又比如LXDDrawLosts://?method=shareMessage&title=分享测试&message=这是林欣达的分享测试&link_url=http://www.jianshu.com/users/0cf7d455eb9e/latest_articles
这代表分享信息到你的app中。这些都是我们自己的应用可以制定的规则,如果有兴趣,可以新浪微博开放平台或者腾讯开放平台,他们的文档中应该有url scheme的传值标准。
说完了通过url scheme传入参数后,怎么把这些参数取出来呢?AppDelegate中提供了application:openURL: sourceApplication: annotation:
方法让我们可以取出传入的值。
在我们通过url scheme跳转到本应用的时候,这个方法就会被系统调用。其中,有两个重要的参数需要我们知道
sourceApplication
这个字符串保存了跳转方app的url Identifier
,就是上文中除了url scheme
以外的另一个字段url
这个链接中存储了跳转的url scheme
以及参数列表,我们通过[url scheme]
方法获取前者;用[url query]
方法获取?
之后的参数列表,然后使用字符串的分隔方法把这些数据读取出来
单纯的二维码数据并没有过于强大的功能,但结合了url scheme的跳转机制后,二维码能够帮助我们的应用获得更加强大的能力,使得我们的应用之间有了更多联系。
文集:iOS开发
本文demo:二维码扫描集成
转载表明链接:http://sindrilin.com/ios-dev/2015/11/01/二维码扫描和应用跳转.html
iOS开发-二维码扫描和应用跳转的更多相关文章
- iOS 原生二维码扫描和生成
代码地址如下:http://www.demodashi.com/demo/12551.html 一.效果预览: 功能描述:WSLNativeScanTool是在利用原生API的条件下封装的二维码扫描工 ...
- iOS - 二维码扫描和应用跳转
序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦, ...
- ipad开发:二维码扫描,摄像头旋转角度问题解决办法
之前一直是在手机上开发,用系统原生二维码扫描功能,一点问题都没有,但是在ipad上,用户是横屏操作的,虽然界面旋转了,是横屏的,但是摄像头里显示的依然是竖屏效果,也就是说从摄像头里看到的和人眼看到的内 ...
- H5混合开发二维码扫描以及调用本地摄像头
今天主管给了我个需求,说要用混合开发,用H5调用本地摄像头进行扫描二维码,我之前有做过原生安卓的二维码扫一扫,主要是通过调用zxing插件进行操作的,其中还弄了个闪光灯.但是纯H5的没接触过,心里没底 ...
- IOS开发 二维码功能的实现
原帖地址:http://yul100887.blog.163.com/blog/static/20033613520121020611299/ 如今二维码随处可见,无论是实物商品还是各种礼券都少不了二 ...
- WindowsPhone8.1 开发-- 二维码扫描
随着 WinRT 8.1 API 的发布,Windows 8.1 和 Windows Phone 8.1 (基于 WinRT) 应用程序的开发模型经历了戏剧性的收敛性.与一些特定于平台的考虑,我们现在 ...
- iOS 系统二维码扫描(可限制扫描区域)
使用 AVFoundation系统库来进行二维码扫描并且限制扫描二维码的范围.(因为默认的是全屏扫描) -(void)beginCode { //1.摄像头设备 AVCaptureDevice *de ...
- iOS 原生二维码扫描(可限制扫描区域)
篇文章的主要原因不是展示如何使用 AVFoundation 来进行二维码扫描,更主要的是限制扫描二维码的范围.(因为默认的是全屏扫描) 项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了 ...
- 【转】 iOS 原生二维码扫描(可限制扫描区域)
在用 AVFoundation 完成扫码后,遇到2个问题: 1,如何限制扫描范围? 2.条形码如何扫描? 一位朋友的文章帮助了我,特地转来,可以帮到有需要的朋友. 原文:http://blog.csd ...
随机推荐
- Parallel.js初探
今天闲着看了一下Parallel.js.这个库暂时貌似还没有什么中文的介绍(可能暂时用的人都不多吧).所以就只能上github找它得源码和介绍看看了.貌似它的代码也不多,以后可以深入研究一下. 先简单 ...
- linux c学习笔记----互斥锁属性
转自:http://lobert.iteye.com/blog/1762844 互斥锁属性 使用互斥锁(互斥)可以使线程按顺序执行.通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程. ...
- sp_executesql的用法
之前做项目的时候负责一个成绩分析的模块儿,写存储过程的时候因为考试的科目是不固定的,所以导致查找成绩的sql语句也是动态的,就用到了sp_executesql,下面就来说一说它的用法 需求:表名是动态 ...
- Linux学习笔记(13)权限管理
1 ACL权限 (1)简介和开启方式 ACL(Access Control List)权限的目的是在提供传统的owner.group.others的read.write.execute权限之外的局部权 ...
- 对于JSP的调试
在eclipse中调试JSP 我换了图片但是网页中的图片却不变化 我删了工程里的图片还是没用 看了一下Tomcat根目录..貌似也是没有的.. 最后我考虑换了HTML中图片的名字..并且更改了替换的图 ...
- 【设计模式】MVC模式
MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式.这种模式用于应用程序的分层开发. Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO.它 ...
- cf #365b 巧妙的统计
Mishka and trip time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- python 继承
继承一个类 如果已经定义了Person类,需要定义新的Student和Teacher类时,可以直接从Person类继承: class Person(object): def __init__(self ...
- no-jquery 03 Ajax
Ajax Requests GETting var xhr = new XMLHttpRequest(); xhr.open('GET', encodeURI('myservice/username? ...
- 关于jquery中 跳出each循环的方法
最近在项目中用带了jquery,在使用each循环遍历时在满足一定条件就跳出,发现break不好使,最终原来 用 return false;便可解决.