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

作者: sindri的小巢 | 来源:发表于2015-11-01 13:23 被阅读26171次

序言

前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢?

在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


1.png

展开新增的字典,我们修改其中的URL Identifier以及新增加一个字段
URL Schemes。
Identifier用来跳转后,让跳转应用识别从哪里跳转过来的,我们可以设置为bundleID反转,来确保其特殊性。
URL Schemes是一个数组,我们将在这个数组里面自定义自己的url schemes,这里我们填写应用名。最终效果如下:


9A8E2746-D1D9-4BC2-81FE-23E13C5EF202.png

接着,我们就可以在其他应用中通过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)发现和预期的不一样,因为这个属性是以屏幕右上角为坐标原点,并且宽高的顺序要对换过来

1.jpg
如图所示,由于坐标系的不同,原本CGRectMake(0.3, 0.35, 0.4, 0.3)到了新坐标系中就变成了CGRectMake(0.35, 0.3, 0.3, 0.4)。那么大家设置成新的扫描范围之后,重新运行扫描程序,看看效果——然而,我们发现并不能扫描成功,这是因为这个扫描区域不仅仅是坐标系原点发生了改变。如下图所示 1.png
按照上面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 用户id
  • title 分享标题
  • 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

相关文章

  • 生成app的二维码下载地址

    iOS中如何做到和安卓里一样通过扫描二维码直接下载应用呢?这里扫描二维码后只能跳转到appstore的应用下载页面...

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

    序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分...

  • 网站链接

    扫描二维码自动识别手机系统(Android/IOS)跳转不同页面

  • iOS开发:二维码扫描与生成(扫描篇)

    iOS开发中经常要用到生成二维码与扫描二维码的功能,iOS7开始,系统支持原生的扫描二维码,iOS7 扫描二维码可...

  • iOS开发之二维码扫描

    iOS开发之二维码扫描 在 iOS7 以前,在IOS中实现二维码和条形码扫描,我们所知的有,两大开源组件 ZBar...

  • 时光么

    时光么 应用简介: 一,扫描二维码: 1..扫描二维码或条形码, 2.能够跳转到对应应用并实现对应功能, 3.也可...

  • iOS 二维码扫描

    iOS开发中 二维码扫描 前言 在移动开发中二维码扫描这种事情越来越常见了,在iOS中我选择了用ZBar这个第三方...

  • 应用之间的跳转和数据传递

    iOS开发拓展篇—应用之间的跳转和数据传递 IOS APP之间跳转通讯 应用之间调用 UIApplication类...

  • 点击按钮扫描二维码

    本文实现是的效果是,点击按钮跳转到扫描二维码界面,扫描出来后跳转到二维码指定的网页,把二维码和网址分别展示在页面上...

  • IOS二维码(ZXingObjc)

    IOS二维码(ZXingObjc) 前言 公司最近上线一款产品,是通过二维码扫描登录。开发阶段的时候使用的是IOS...

网友评论

  • 雪_晟:楼主有没有试过,你的二维码图片无法转成data
  • 897948f5dfd3:你的rectOfInterest说的不对
    The value of this property is a CGRect that determines the receiver's rectangle of interest for each frame of video. The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata. Specifying a rectOfInterest may improve detection performance for certain types of metadata. The default value of this property is the value CGRectMake(0, 0, 1, 1). Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.
    这个基础点还是扫描区域的左上角.只不过都是使用比例系数.
  • 目染江夏:问个小问题 ,你试过扫描纯绿色的二维码吗?不好使的。。。。
  • e5b962a502c2:@Sindri的小巢 大神,运行起来就崩溃了,有没有最新的demo,给个链接,谢谢了!
  • 30d430c75985:是不是设置的扫描试图是按照手机尺寸来设置的,用pad扫描,frame错误,引起的崩溃
  • 30d430c75985:我在pad上系统10.11的运行你的demo点击扫描直接崩溃,但是在手机上可以,没查到原因.....求解
    30d430c75985:@Sindri的小巢 但是在pad上有个问题,点击扫描差不多10秒左右才会启动相机,手机上就没这问题
    30d430c75985:@Sindri的小巢已经解决了,调用相机的时候方法不一样,扫描的地方也需要改动,
    sindri的小巢:@PoorHm 没有兼容ipad,因为ipad的扫描需要改动
  • 7426426529e1:ios新手。我想试着调整扫描框的Y坐标,可是框动了,扫描位置不动,还是在原来的位置,请问在哪个方法里面调呢?
  • 风不会停歇:那怎么创建一个url scheme的二维码?
  • 丿尛峯:把文件拖到工程里报”Undefined symbols for architecture arm64“ 错误 不支持arm64吗?
    sindri的小巢:@丿尛峯 :flushed:我用64位测试的都没问题
  • 3a169b0787bc:感谢博主分享。发现有个问题。
    sourceApplication 这个字符串保存了跳转方app的url Identifier。这一点好像有误。
    sourceApplication 应该是跳转方App的bundleID。
    3a169b0787bc:@真是艹0 还有个问题 就是传的信息里有汉字的时候。 无法成功跳转。
  • e4d93d6aae84: :joy: 哥,这是只扫二维码啊,你在代码里写#define REMINDTEXT @"将二维码/条码放入框内,即可自动扫描"误导人啊
    sindri的小巢:@冰阳life 你看看我代码里是不是露填了条形码参数
  • d053345b0b60:我一直以为:rectOfInterest 设置后,扫描区域不准确是苹果自身的Bug,看了你的文章才知道原来一直是设置的不对啊,大谢!!! :+1:
  • e14dcf1ff587:楼主您好,请问您是否有关于iOS 条形码的demo,我项目中遇到难题了,急求。谢谢!
    e14dcf1ff587:@Sindri的小巢 好的,谢谢!
    sindri的小巢:@妮妮巴耶娃 没做过条形码的需求
  • e14dcf1ff587:下载代码后,一点击按钮就会出现异常,两个按钮都是。关键本人是新手,不会调异常,该怎么办,求作者帮忙
    sindri的小巢:@妮妮巴耶娃 你看看支持的所有码类型,然后添加进去
    e14dcf1ff587:@Sindri的小巢 在MAC上,Avcapture 类好像没写完整,里面的Metada类型不支持,现在在用真机测试,求帮忙
    sindri的小巢:@妮妮巴耶娃 有空我看看,在什么设备上运行的?
  • 大怪猿:博主 这个可以实现二维码登陆吗
    sindri的小巢:@大怪猿 对
    大怪猿:@Sindri的小巢 这是个问题 这是后台做的吗 就是保证一个账号只能被一台设备登录
    sindri的小巢:@大怪猿 没问题,但是关键在于如果扫描二维码就能登录,登录谁的账号?多台设备扫描同一个二维码导致同时登录一个账号是否合理
  • 花色衬衫:怎么判断扫描的内容是文本还是网址。扫描出来的内容应该用什么接收?比如扫描的是一段文本, 是不是应该用uilab 来展示?如果是url 是不是应该用 uiwebview展示? 那么怎么确定自己扫描的结果是 文本还是 url或者照片呢?
    sindri的小巢:@花色衬衫 这个要自己在app里判断
  • 0200a9609930:有代码吗?可以共享看看不?
    0200a9609930:@Sindri的小巢 好 谢谢
    sindri的小巢:@0200a9609930 最下面有demo链接
  • 喝杯开水压压惊:有没有能实现相册图片的
  • Inlight先森:运行Demo 点击后 直接crash
    sindri的小巢:对,因为模拟器不支持打开摄像头
    Inlight先森:是不是用模拟器就会crash
    sindri的小巢:@Dalla尹 崩溃日志输出什么错误?模拟器运行吗?
  • _誌念:二维码

本文标题:iOS开发-二维码扫描和应用跳转

本文链接:https://www.haomeiwen.com/subject/ysqqhttx.html