ios7 苹果原生二维码扫描

在ios7苹果推出了二维码扫描,以前想要做二维码扫描,只能通过第三方ZBar与ZXing。

ZBar在扫描的灵敏度上,和内存的使用上相对于ZXing上都是较优的,但是对于 “圆角二维码” 的扫描确很困难。

ZXing 是 Google Code上的一个开源的条形码扫描库,是用java设计的,连Google Glass 都在使用的。但有人为了追求更高效率以及可移植性,出现了c++ port. Github上的Objectivc-C port,其实就是用OC代码封装了一下而已,而且已经停止维护。这样效率非常低,在instrument下面可以看到CPU和内存疯涨,在内存小的机器上很容易崩溃。

AVFoundation无论在扫描灵敏度和性能上来说都是最优的。

首先要导入#import <AVFoundation/AVFoundation.h>框架

完成二维码扫描大致有十个步骤:

    // 1.获取输入设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // 2.创建输入对象
    NSError *error;
    AVCaptureDeviceInput *inPut = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];

    if (inPut == nil) {
        UIAlertView *aler = [[UIAlertView alloc] initWithTitle:@"提示" message:@"设备不可用" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [self.view addSubview:aler];
        [aler show];
        return;
    }

    // 3.创建输出对象
    AVCaptureMetadataOutput *outPut = [[AVCaptureMetadataOutput alloc] init];

    // 4.设置代理监听输出对象的输出流  (说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验)
    [outPut setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    // 5.创建会话
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    self.session = session;

    // 6.将输入和输出对象添加到会话
    if ([session canAddInput:inPut]) {
        [session addInput:inPut];
    }
    if ([session canAddOutput:outPut]) {
        [session addOutput:outPut];
    }

    // 7.告诉输出对象, 需要输出什么样的数据  // 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
    [outPut setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];

    // 8.创建预览图层
    AVCaptureVideoPreviewLayer *preViewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];
    preViewLayer.frame = self.view.bounds;
    [self.view.layer insertSublayer:preViewLayer atIndex:0];

    // 9.设置扫面范围
    outPut.rectOfInterest = CGRectMake(0.2, 0.18, 0.6, 0.5);

    // 10.设置扫描框
    UIView *boxView = [[UIView alloc] initWithFrame:CGRectMake(0.2 * SrceenW, 0.18 * SrceenH, 0.6 * SrceenW, 0.5 * SrceenH)];
    self.boxView = boxView;

    boxView.layer.borderColor = [UIColor yellowColor].CGColor;
    boxView.layer.borderWidth = 3;

    [self.view addSubview:boxView];

    // 设置扫描线
    CALayer *scanLayer = [[CALayer alloc] init];
    self.scanLayer = scanLayer;

    scanLayer.frame = CGRectMake(0, 0, boxView.bounds.size.width, 2);
    scanLayer.backgroundColor = [UIColor redColor].CGColor;
    [boxView.layer addSublayer:scanLayer];

    // 开始扫描
    [session startRunning];

其中第9个步骤是可以优化内存的

@property(nonatomic) CGRect rectOfInterest;

这个属性大致意思就是告诉系统它需要注意的区域,大部分APP的扫码UI中都会有一个框,提醒你将条形码放入那个区域,这个属性的作用就在这里,它可以设置一个范围,只处理在这个范围内捕获到的图像的信息。如此一来,我们代码的效率又会得到很大的提高,在使用这个属性的时候。需要几点注意:

1、这个CGRect参数和普通的Rect范围不太一样,它的四个值的范围都是0-1,表示比例。

2、经过测试发现,这个参数里面的x对应的恰恰是距离左上角的垂直距离,y对应的是距离左上角的水平距离。

3、宽度和高度设置的情况也是类似。

-----------------------------以下是源码:

#import "ScanQrcodeVController.h"

@protocol ScanQrcodeVControllerDelegate <NSObject>
// 二维码返回结果
-(void)scanQrcodeWithNString:(NSString *) ruselt;
@end
@interface ScanQrcodeVController : UIViewController
@property (nonatomic, weak) id<ScanQrcodeVControllerDelegate>delegate;
@end

#import "ScanQrcodeVController.m"

@interface ScanQrcodeVController ()<AVCaptureMetadataOutputObjectsDelegate>
// 会话
@property (nonatomic, strong) AVCaptureSession *session;
// 定时器
@property (nonatomic, strong) CADisplayLink *link;
// 扫描线
@property (nonatomic, strong) CALayer *scanLayer;
// 扫描框
@property (nonatomic, weak) UIView *boxView;
/// 保存二维码结果
@property (nonatomic, copy) NSString *string;
@end

@implementation ScanQrcodeVController
- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"NavBack"] style:UIBarButtonItemStylePlain target:self action:@selector(goBack)];

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(doneClick)];

    [self scanCode];
}

-(void)scanCode {

    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updataFrame)];
    self.link = link;
    link.frameInterval = 3;

    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

    // 1.获取输入设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // 2.创建输入对象
    NSError *error;
    AVCaptureDeviceInput *inPut = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];

    if (inPut == nil) {
        UIAlertView *aler = [[UIAlertView alloc] initWithTitle:@"提示" message:@"设备不可用" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [self.view addSubview:aler];
        [aler show];
        return;
    }

    // 3.创建输出对象
    AVCaptureMetadataOutput *outPut = [[AVCaptureMetadataOutput alloc] init];

    // 4.设置代理监听输出对象的输出流  说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验
    [outPut setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    // 5.创建会话
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    self.session = session;

    // 6.将输入和输出对象添加到会话
    if ([session canAddInput:inPut]) {
        [session addInput:inPut];
    }
    if ([session canAddOutput:outPut]) {
        [session addOutput:outPut];
    }

    // 7.告诉输出对象, 需要输出什么样的数据  // 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
    [outPut setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];

    // 8.创建预览图层
    AVCaptureVideoPreviewLayer *preViewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];
    preViewLayer.frame = self.view.bounds;
    [self.view.layer insertSublayer:preViewLayer atIndex:0];

    // 9.设置扫面范围
    outPut.rectOfInterest = CGRectMake(0.2, 0.18, 0.6, 0.5);

    // 10.设置扫描框
    UIView *boxView = [[UIView alloc] initWithFrame:CGRectMake(0.2 * SrceenW, 0.18 * SrceenH, 0.6 * SrceenW, 0.5 * SrceenH)];
    self.boxView = boxView;

    boxView.layer.borderColor = [UIColor yellowColor].CGColor;
    boxView.layer.borderWidth = 3;

    [self.view addSubview:boxView];

    // 设置扫描线
    CALayer *scanLayer = [[CALayer alloc] init];
    self.scanLayer = scanLayer;

    scanLayer.frame = CGRectMake(0, 0, boxView.bounds.size.width, 2);
    scanLayer.backgroundColor = [UIColor redColor].CGColor;
    [boxView.layer addSublayer:scanLayer];

    // 开始扫描
    [session startRunning];
}

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {

    if (metadataObjects.count > 0) {

        // 停止扫描
        [self.session stopRunning];
        // 移除CADisplayLink对象
        [self.link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
        self.link = nil;

        // 取出数据
        AVMetadataMachineReadableCodeObject *obj = [metadataObjects lastObject];

        self.string = obj.stringValue;
    }

    NSLog(@"扫描--%@",self.string);
    [NSThread sleepForTimeInterval:1.0];
}

-(void)updataFrame {

    CGRect frame = self.scanLayer.frame;

    if (self.scanLayer.frame.origin.y > self.boxView.frame.size.height) {
        frame.origin.y = -20;
        self.scanLayer.frame = frame;
    }else{
        frame.origin.y += 3;
        self.scanLayer.frame = frame;
    }

}

-(void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
    // 记得释放CADisplayLink对象
    if (self.link != nil) {
        [self.link invalidate];
        self.link = nil;
    }
}

// 返回上一个界面
-(void)goBack {

    [self.navigationController popViewControllerAnimated:YES];
}

// 二维码扫描完成
-(void)doneClick {

    // 设置代理
    if ([self.delegate respondsToSelector:@selector(scanQrcodeWithNString:)]) {
        [self.delegate scanQrcodeWithNString:self.string];
    }

    [self.navigationController popToRootViewControllerAnimated:YES];
}
@end
时间: 2024-10-24 04:07:42

ios7 苹果原生二维码扫描的相关文章

苹果原生二维码扫描功能——可限制扫描区域

使用原生的好处就是扫描特别快效率特别高,使用  AVFoundation 来进行二维码扫描,更主要的是限制扫描二维码的范围.(默认的是全屏扫描) 首先是要用到的几个类 @property ( strong , nonatomic ) AVCaptureDevice * device; @property ( strong , nonatomic ) AVCaptureDeviceInput * input; @property ( strong , nonatomic ) AVCaptureMe

二维码扫描(iOS原生二维码扫描)

一.关于二维码扫描的第三方库有很多:例如比较常用的两个 1.ZBar SDK ZBar为我们提供了两种使用方式,一种是直接调用ZBar提供的ZBarReaderViewController打开一个扫描界面,另一种方式是使用ZBar提供的可以嵌在其他视图中的ZBarReaderView,实际项目中我们更可能会使用第二种方式,这可以让我们对界面做更多的定制,详细的百度查找相关文档来看. 2.ZXing(Github镜像地址)是一个开源的条码生成和扫描库(开源协议为Apache2.0).它不但支持众多

iOS之原生二维码扫描

做iOS的二维码扫描,有两个第三方库可以选择,ZBar和ZXing.今天要介绍的是iOS7.0后AVFoundation框架提供的原生二维码扫描. 首先需要添加AVFoundation.framework框架到你工程中build phase的"Link Binary With Libraries"之下,然后就可以开始了. 一.做好准备工作,搭建UI IBOutlet.IBAction如下: @property (weak, nonatomic) IBOutlet UIView *vie

iOS:原生二维码扫描

做iOS的二维码扫描,有两个第三方库可以选择,ZBar和ZXing.今天要介绍的是iOS7.0后AVFoundation框架提供的原生二维码扫描. 首先需要添加AVFoundation.framework框架到你工程中build phase的"Link Binary With Libraries"之下,然后就可以开始了. 一.做好准备工作,搭建UI UI效果如图 IBOutlet.IBAction如下: @property (weak, nonatomic) IBOutlet UIVi

iOS 原生二维码扫描(可限制扫描区域)

写这篇文章的主要原因不是展示如何使用 AVFoundation   来进行二维码扫描,更主要的是限制扫描二维码的范围.(因为默认的是全屏扫描) 项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了苹果原生的扫描. 原生的好处就是扫描特别快效率特别高,但是遇到一个问题就是不知道怎么去限制扫描范围. 还是先简单说一下怎么使用来进行二维码扫描吧. 首先是要用到的几个类 @property (strong,nonatomic)AVCaptureDevice * device; @propert

【转】 iOS 原生二维码扫描(可限制扫描区域)

在用 AVFoundation 完成扫码后,遇到2个问题: 1,如何限制扫描范围? 2.条形码如何扫描? 一位朋友的文章帮助了我,特地转来,可以帮到有需要的朋友. 原文:http://www.2cto.com/kf/201411/356046.html 写这篇文章的主要原因不是展示如何使用 AVFoundation 来进行二维码扫描,更主要的是限制扫描二维码的范围.(因为默认的是全屏扫描) 项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了苹果原生的扫描. 原生的好处就是扫描特别快效

iOS 原生二维码扫描,带扫描框和扫描过程动画

在代码中使用了相对布局框架Masonry 准备两张图片,一张是扫描边框,一张是扫描时的细线分别命名 scanFrame.png和scanLine.png并提前放入工程 导入相对布局头文件 #define MAS_SHORTHAND #define MAS_SHORTHAND_GLOBALS #import "Masonry.h" 导入依赖头文件 #import <AVFoundation/AVFoundation.h> 具体代码如下: static const char *

iOS 原生二维码扫描

哎 关于限制扫码范围的控制,弄了老夫好久,还是不尽如意 .h 1 // 2 // LIUScanTwoDimensionalCode.h 3 // YouYouShoppingCenter 4 // 5 // Created by liujun on 15/7/28. 6 // Copyright (c) 2015年 刘俊. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 #import <AVFoundation/AVF

一个不同于ZBAR的二维码扫描与识别。

现在好多人使用二维码用到第三方 ZBar,往往被不支持模拟器所困扰.经过楼主的不懈努力,终于一款原生二维码扫描识别与生成工具类完成了.大家可以轻易的添加二维码的头像,改变二维码的样式(颜色修改要慎重,有时候颜色修改的不合适会导致,二维码识别失败).废话不多说直接给demo地址:https://github.com/zcs110/scanQR.git   Code4上直接搜索scanQR就可以了.