转载自: http://sindrilin.com/ios-dev/2015/11/01/二维码扫描和应用跳转.htmlhtml
前面咱们已经调到过怎么制做二维码,在咱们可以生成二维码以后,如何对二维码进行扫描呢?ios
在iOS7以前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar。使用时集成麻烦,出错也不方便调试。在iOS7以后,苹果自身提供了二维码的扫描功能,从效率上来讲,原生的二维码远高于这些第三方框架。本文讲解如何使用原生框架实现二维码扫描功能,而且进行扫描后的项目跳转。数组
二维码扫描须要获取摄像头并读取照片信息,所以咱们须要导入系统的AVFoundation
框架,建立视频会话。咱们须要用到一下几个类:xcode
在使用第三方登录、分享sdk的时候,咱们的项目会在本机安装有目标平台的应用的状况下进行应用跳转,而且传递信息过去。这在沙盒机制下的iOS应用而言,理应是不符合规则的。可是,iOS SDK给咱们提供了一个叫作url scheme的机制来实现这个功能。微信
url scheme让咱们能够像使用Safari打开网页的方式跳转到其余应用中,并使用相似网络请求的GET请求的参数拼凑方式来在不一样应用之间传递数据。网络
使用url scheme的第一步是在项目的info.plist文件中添加新row,命名为URL typessession
展开新增的字典,咱们修改其中的URL Identifier以及新增长一个字段
URL Schemes。
Identifier用来跳转后,让跳转应用识别从哪里跳转过来的,咱们能够设置为bundleID反转,来确保其特殊性。
URL Schemes是一个数组,咱们将在这个数组里面自定义本身的url schemes,这里咱们填写应用名。最终效果以下:app
接着,咱们就能够在其余应用中经过openURL:方法打开咱们的app。框架
二维码扫描的步骤:ide
一、建立设备会话对象,用来设置设备数据输入
二、获取摄像头,而且将摄像头对象加入当前会话中
三、实时获取摄像头原始数据显示在屏幕上
四、扫描到二维码/条形码数据,经过协议方法回调
会话对象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的跳起色制后,二维码可以帮助咱们的应用得到更增强大的能力,使得咱们的应用之间有了更多联系。