本帖最后由 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形式的网页内容,具体代码如下: - #import <AVFoundation/AVFoundation.h>
- #import <SafariServices/SafariServices.h>
复制代码 2. 创建会话 由于iOS系统用一个会话对象管理扫描过程,所以在扫描时第一步是创建会话对象。会话使用AVCaptureSession类。创建会话之前首先要定义一个属性保存会话对象,代码如下: - @property (nonatomic,strong) AVCaptureSession *session;
复制代码 然后创建会话对象,并赋值给这个属性。代码如下: - self.session = [[AVCaptureSession alloc] init];
复制代码 3. 创建输入设备 要扫描二维码,必须用到摄像头,摄像头是输入设备的一种。输入设备要关联到会话,指定扫描会话所使用的输入设备。输入设备用AVCaptureDeviceInput类表示。具体代码如例1所示: 例1 ViewController.m文件中创建输入对象 - //创建设备对象并设置为摄像头类型
- AVCaptureDevice *device = [AVCaptureDevice
- defaultDeviceWithMediaType:AVMediaTypeVideo];
- //根据创建的设备对象生成输入设备
- AVCaptureDeviceInput *input = [AVCaptureDeviceInput
- deviceInputWithDevice:device error:nil];
- //将输入设备关联到会话
- if ([self.session canAddInput:input]) {
- [self.session addInput:input];
- }
复制代码 在例1中,第1-3行创建了一个设备对象,并指定设备的类型为视频输入,创建出的设备对象一般是后置摄像头。第4-6行根据这个设备对象生成输入设备,第7-10行代码判断该输入设备是否能成功关联到会话,如果可以,则执行关联。 4. 创建输出对象 在输入设备扫描到二维码以后,输出对象负责识别二维码包含的信息,并将识别到的信息传递出来。输出对象使用AVCaptureMetadataOutput类表示。示例代码如例2所示: 例2 ViewController.m文件中创建输出对象 - //创建一个输出对象
- AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
- //输出对象关联到会话
- if ([self.session canAddOutput:output]) {
- [self.session addOutput:output];
- }
- //设置元数据类型,是QR二维码
- output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
- //设置代理,得到解析结果
- [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
复制代码 例2的代码中,第2行创建了输出对象,第4-5行判断该输出对象是否可以关联到会话,如何可以,就执行关联。第8行设置输出对象的元数据类型为AVMetadataObjectTypeQRCode,也就是二维码类型。第10行设置输出对象的代理,以后由代理来处理输出对象识别到的信息。 5. 创建显示扫描的层 在摄像头扫描时,需要创建一个特殊的CALayer来显示摄像头拍摄到的视频内容,这个类是CALayer的子类,叫做AVCaptureVideoPreviewLayer。要创建这个AVCaptureVideoPreviewLayer对象,首先要定义一个属性保存它。示例代码如下: - @property (nonatomic,strong) AVCaptureVideoPreviewLayer *preLayer;
复制代码 然后创建这个层对象,并赋值给该属性。示例代码如例3所示: 例3 ViewController.m文件中创建显示扫描的层 - //创建一个特殊的层
- self.preLayer = [[AVCaptureVideoPreviewLayer alloc]
- initWithSession:self.session];
- //设置尺寸并添加到视图树
- self.preLayer.frame = self.view.bounds;
- [self.view.layer addSublayer:self.preLayer];
复制代码 在例3的代码中,第2-3行创建了一个层对象,第5行设置层的尺寸与控制器视图的尺寸相同,第6行将扫描层添加到控制器的视图树中。 6. 开启会话 到这一步,会话已经准备好了,使用会话对象的startRunning方法开启会话,则摄像头被打开,扫描开始。具体代码如下: - [self.session startRunning];
复制代码 7. 获取二维码信息 识别到的二维码信息由输出对象交给代理对象处理。AVCaptureMetadataOutput类规定一个协议,叫做AVCaptureMetadataOutputObjectsDelegate,该协议只有一个方法,该方法的参数metadataObjects里就包含了识别到的二维码信息。该方法定义如下: - - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
复制代码 在创建输出对象时已将控制器设置为输出对象的代理。控制器要成为它的代理,首先必须遵守AVCaptureMetadataOutputObjectsDelegate,示例代码如下: - @interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
复制代码 然后要实现代理方法。示例代码如例4所示: 例4 ViewController.m文件中实现代理方法 - - (void)captureOutput:(AVCaptureOutput *)captureOutput
- didOutputMetadataObjects:(NSArray *)metadataObjects
- fromConnection:(AVCaptureConnection *)connection
- {
- //停止会话
- [self.session stopRunning];
- //移除显示扫描层
- [self.preLayer removeFromSuperlayer];
- if (metadataObjects.count > 0){
- AVMetadataMachineReadableCodeObject *object = [metadataObjects
- firstObject];
- NSLog(@"%@",object.stringValue);
- //判断是否为网页
- if ([obj.stringValue hasPrefix:@"http://"]) {
- //是网址,使用浏览器框架
- //创建控制器
- SFSafariViewController *safariVc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
- //进行modal展示
- [self presentViewController:safariVc animated:YES completion:nil];
- }
- }
- }
复制代码 在例4的代理方法中,第6行停止会话,即停止扫描。第8行将创建的显示扫描的层从控制器的视图树上移除。第9-13行首先判断metadataObjects中是否有对象,如果有则取出该对象,并将对象的stringValue字符串值打印到控制器。 编写完代码,执行程序,就可以在控制台打印出识别到的二维码信息了。这里扫描图4中左边的二维码,如果控制台打印出一段网页链接,说明程序成功地识别到这个二维码表示的文字信息。其后13-15对该识别的信息进行了判断,如果为网页链接,则在16-19使用SafariServices框架根据链接在界面上展示类Safari形式的网页内容,图5为展示的网页内容. 图4 二维码示例 图5
精华推荐:
|