A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 Simpon 于 2016-10-19 11:52 编辑

版权声明:本文为作者原创文章,未经作者允许不得转载。       

二维码在app中的使用越来越广泛,二维码能存储汉字、数字、字母和图片等信息, 支付软件用二维码确定支付信息,社交软件用二维码添加联系人,下载页面用二维码链接到App Store的下载链接等等。
     二维码(2-dimensional barcode)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的技术。在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理。它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。
     常用的二维码是QR码(QR Code),是一种矩阵二维码符号码。它的示例和结构如图1所示。
                                 
图1 QR码示例和结构
     扫描二维码已成为实际开发中的常用功能,接下来就围绕如何扫描二维码进行详细的分步骤介绍,具体如下:
          1. 导入头文件
            由于扫描二维码的相关类都包含在AVFoundation框架中,所以要导入<AVFoundation/AVFoundation.h>头文件,另项目中使用到了iOS9的新特性-SafariServices框架, 该用于在应用界面中根据网页链接展示类Safari形式的网页内容,具体代码如下:
  1. #import <AVFoundation/AVFoundation.h>
  2. #import <SafariServices/SafariServices.h>
复制代码
  2. 创建会话
            由于iOS系统用一个会话对象管理扫描过程,所以在扫描时第一步是创建会话对象。会话使用AVCaptureSession类。创建会话之前首先要定义一个属性保存会话对象,代码如下:
  1. @property (nonatomic,strong) AVCaptureSession *session;
复制代码
            然后创建会话对象,并赋值给这个属性。代码如下:
  1. self.session = [[AVCaptureSession alloc] init];
复制代码
  3. 创建输入设备
            要扫描二维码,必须用到摄像头,摄像头是输入设备的一种。输入设备要关联到会话,指定扫描会话所使用的输入设备。输入设备用AVCaptureDeviceInput类表示。具体代码如例1所示:
     例1  ViewController.m文件中创建输入对象
  1. //创建设备对象并设置为摄像头类型
  2. AVCaptureDevice *device = [AVCaptureDevice
  3. defaultDeviceWithMediaType:AVMediaTypeVideo];
  4. //根据创建的设备对象生成输入设备
  5. AVCaptureDeviceInput *input = [AVCaptureDeviceInput
  6. deviceInputWithDevice:device error:nil];
  7. //将输入设备关联到会话
  8. if ([self.session canAddInput:input]) {
  9. [self.session addInput:input];
  10. }
复制代码
            在例1中,第1-3行创建了一个设备对象,并指定设备的类型为视频输入,创建出的设备对象一般是后置摄像头。第4-6行根据这个设备对象生成输入设备,第7-10行代码判断该输入设备是否能成功关联到会话,如果可以,则执行关联。
  4. 创建输出对象
            在输入设备扫描到二维码以后,输出对象负责识别二维码包含的信息,并将识别到的信息传递出来。输出对象使用AVCaptureMetadataOutput类表示。示例代码如例2所示:
例2   ViewController.m文件中创建输出对象
  1. //创建一个输出对象
  2. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  3. //输出对象关联到会话
  4. if ([self.session canAddOutput:output]) {
  5. [self.session addOutput:output];
  6. }
  7. //设置元数据类型,是QR二维码
  8. output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
  9. //设置代理,得到解析结果
  10. [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
复制代码
            例2的代码中,第2行创建了输出对象,第4-5行判断该输出对象是否可以关联到会话,如何可以,就执行关联。第8行设置输出对象的元数据类型为AVMetadataObjectTypeQRCode,也就是二维码类型。第10行设置输出对象的代理,以后由代理来处理输出对象识别到的信息。
          5. 创建显示扫描的层
            在摄像头扫描时,需要创建一个特殊的CALayer来显示摄像头拍摄到的视频内容,这个类是CALayer的子类,叫做AVCaptureVideoPreviewLayer。要创建这个AVCaptureVideoPreviewLayer对象,首先要定义一个属性保存它。示例代码如下:
  1. @property (nonatomic,strong) AVCaptureVideoPreviewLayer *preLayer;
复制代码
            然后创建这个层对象,并赋值给该属性。示例代码如例3所示:
         例3   ViewController.m文件中创建显示扫描的层
  1. //创建一个特殊的层
  2. self.preLayer = [[AVCaptureVideoPreviewLayer alloc]
  3. initWithSession:self.session];
  4. //设置尺寸并添加到视图树
  5. self.preLayer.frame = self.view.bounds;
  6. [self.view.layer addSublayer:self.preLayer];
复制代码
            在例3的代码中,第2-3行创建了一个层对象,第5行设置层的尺寸与控制器视图的尺寸相同,第6行将扫描层添加到控制器的视图树中。
          6. 开启会话
            到这一步,会话已经准备好了,使用会话对象的startRunning方法开启会话,则摄像头被打开,扫描开始。具体代码如下:
  1. [self.session startRunning];
复制代码
          7. 获取二维码信息
            识别到的二维码信息由输出对象交给代理对象处理。AVCaptureMetadataOutput类规定一个协议,叫做AVCaptureMetadataOutputObjectsDelegate,该协议只有一个方法,该方法的参数metadataObjects里就包含了识别到的二维码信息。该方法定义如下:
  1. - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
复制代码
            在创建输出对象时已将控制器设置为输出对象的代理。控制器要成为它的代理,首先必须遵守AVCaptureMetadataOutputObjectsDelegate,示例代码如下:
  1. @interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
复制代码
            然后要实现代理方法。示例代码如例4所示:
        例4  ViewController.m文件中实现代理方法
  1. - (void)captureOutput:(AVCaptureOutput *)captureOutput
  2. didOutputMetadataObjects:(NSArray *)metadataObjects     
  3. fromConnection:(AVCaptureConnection *)connection
  4. {
  5. //停止会话
  6. [self.session stopRunning];
  7. //移除显示扫描层
  8. [self.preLayer removeFromSuperlayer];
  9. if (metadataObjects.count > 0){
  10. AVMetadataMachineReadableCodeObject *object = [metadataObjects
  11. firstObject];
  12. NSLog(@"%@",object.stringValue);
  13. //判断是否为网页
  14. if ([obj.stringValue hasPrefix:@"http://"]) {
  15. //是网址,使用浏览器框架
  16. //创建控制器
  17. SFSafariViewController *safariVc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
  18. //进行modal展示
  19. [self presentViewController:safariVc animated:YES completion:nil];
  20.                                                                     }
  21.                                                  }
  22. }
复制代码
            在例4的代理方法中,第6行停止会话,即停止扫描。第8行将创建的显示扫描的层从控制器的视图树上移除。第9-13行首先判断metadataObjects中是否有对象,如果有则取出该对象,并将对象的stringValue字符串值打印到控制器。
            编写完代码,执行程序,就可以在控制台打印出识别到的二维码信息了。这里扫描图4中左边的二维码,如果控制台打印出一段网页链接,说明程序成功地识别到这个二维码表示的文字信息。其后13-15对该识别的信息进行了判断,如果为网页链接,则在16-19使用SafariServices框架根据链接在界面上展示类Safari形式的网页内容,图5为展示的网页内容.      

      图4  二维码示例                        

图5



精华推荐:


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马