在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>框架

其次还需要授权应用可以访问相机

    // 判断相机是否授权使用相机AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];if(status == AVAuthorizationStatusAuthorized) {} else if(status == AVAuthorizationStatusDenied){// NSLog(@"denied不允许");return ;} else if(status == AVAuthorizationStatusNotDetermined){[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {if(granted){
//                NSLog(@"允许");} else {
//                NSLog(@"不允许");return;}}];}//    typedef enum
//        AVAuthorizationStatusNotDetermined = 0, // 用户尚未做出选择这个应用程序的问候
//        AVAuthorizationStatusRestricted,        // 此应用程序没有被授权访问的照片数据。可能是家长控制权限
//        AVAuthorizationStatusDenied,            // 用户已经明确否认了这一照片数据的应用程序访问
//        AVAuthorizationStatusAuthorized         // 用户已经授权应用访问照片数据} CLAuthorizationStatus;

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

    // 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、宽度和高度设置的情况也是类似。

/// 经过测试  使用rectOfInterest 更改扫描范围 并没有很好的可控制范围,如果想达到想微信那样,只有在固定的扫描框中才可以扫描成功

可以使用以下设置,在

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection; 方法中,判断二维码的三个坐标点是否在扫描框中。

for (id objects in metadataObjects) {// 判断检测到的对象类型if (![objects isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {return;}// 转换对象坐标
AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)[preViewLayer transformedMetadataObjectForMetadataObject:objects];// 判断扫描范围if (!CGRectContainsRect(self.boxView.frame, obj.bounds)) {continue;}}

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

#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];

  

// 判断相机是否授权使用相机

AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

if(status == AVAuthorizationStatusAuthorized) {

} else if(status == AVAuthorizationStatusDenied){

// NSLog(@"denied不允许");

return ;

} else if(status == AVAuthorizationStatusNotDetermined){

[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {

if(granted){

//                NSLog(@"允许");

} else {

//                NSLog(@"不允许");

return;

}

}];

// 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 {    for (id objects in metadataObjects) {

// 判断检测到的对象类型

if (![objects isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {

return;

}

// 转换对象坐标

AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)[preViewLayer transformedMetadataObjectForMetadataObject:objects];

// 判断扫描范围

if (!CGRectContainsRect(self.boxView.frame, obj.bounds)) {

continue;

     }

// 设置代理

      if ([self.delegate respondsToSelector:@selector(scanQrcodeWithNString:)]) {

[self.delegate scanQrcodeWithNString:obj.stringValue];

     }

     // 停止扫描

     [self.session stopRunning];

// 移除CADisplayLink对象

[self.link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

self.link = nil;

}

}-(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

转载于:https://www.cnblogs.com/Mr-Ygs/p/4904710.html

ios7 苹果原生二维码扫描(和微信类似)相关推荐

  1. 苹果原生二维码生成与扫描及生成的二维码不清楚的解决方案

    苹果原生二维码生成与扫描及生成的二维码不清楚的解决方案 参考文章: (1)苹果原生二维码生成与扫描及生成的二维码不清楚的解决方案 (2)https://www.cnblogs.com/CoderEYL ...

  2. iOS原生二维码扫描(一)

    首先搭建一个最初步的能识别出二维码信息的最基本框架: @interface ScanCodeViewController ()<AVCaptureMetadataOutputObjectsDel ...

  3. iOS 原生二维码扫描和生成

    代码地址如下: http://www.demodashi.com/demo/12551.html 一.效果预览: 功能描述:WSLNativeScanTool是在利用原生API的条件下封装的二维码扫描 ...

  4. iOS 7原生二维码扫描中文gbk编码乱码的解决

    有的二维码生成的含有中文的数据编码是GBK编码,如百度二维码生成器,使用系统原生二维码扫描就会出现乱码,于是开始网上查阅,该试的方法都尝试过了,终于功夫不负有心人,问题得到了解决,先上代码 NSStr ...

  5. Android 二维码扫描(仿微信界面),根据Google zxing

    Android 二维码扫描(仿微信界面),根据Google zxing Android项目开发中经常会用到二维码扫描,例如登陆.支付等谷歌方面已经有了一个开源库(地址: https://github. ...

  6. 苹果原生二维码扫描器

    项目中一直用的ZBar的扫描,后来发现速度明显和微信差很多,然后就想着替换成原生的,自己动手弄了一个简陋的扫描器,支持相册扫描,手电筒等.大神勿喷. 项目连接:https://github.com/S ...

  7. iOS 开发AVFoundation系统原生二维码扫描实现

    /* 先在项目中导入AVFoundation.framework框架 */ #import <UIKit/UIKit.h> #import <AVFoundation/AVFound ...

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

    废话不多说,直接上代码 **先声明几个类** @interface QRCodeController ()<AVCaptureMetadataOutputObjectsDelegate>@ ...

  9. iOS--AVFoundation原生二维码与一维码扫描

    概述 实现二维码和条形码扫描,两大开源组件ZBar与ZXing ZBar: 扫描灵敏性,内存较优,但"圆角二维码"扫描比较困难. ZXing: Google Code上的一个开源的 ...

最新文章

  1. BusinessFrameWork
  2. Mac没有winnt格式_8款优秀软件,让你使用mac更舒适
  3. 第4章 类型基础 -- 4.1 所有类型都从System.Object派生
  4. 标签体系、用户分群、用户画像「玩味」解读,你沦为形式主义了吗?
  5. CIKM 2021 | Deep Retrieval:字节跳动深度召回模型论文精读
  6. Java黑皮书课后题第7章:7.9(找出最小元素)使用下面的方法头编写一个方法,求出一个整数数组中的最小元素。编写测试程序,提示用户输入10个数字,调用这个方法返回最小值,并显示这个最小值
  7. android 通过webview调起支付宝app支付
  8. js里面拼接代码和使用ModelAndView
  9. python创建单例模式_Python单例模式的四种创建方式实例解析
  10. C#LeetCode刷题之#671-二叉树中第二小的节点(Second Minimum Node In a Binary Tree)
  11. 月薪2万是一种怎样的人生体验?
  12. java gui 保存文件_用JAVA编写一个GUI记事本程序,实现文本的输入,保存,修改,打开操作...
  13. MySQL 高阶语句之函数存储
  14. SpringBoot整合CXF框架实现Webservice服务端
  15. 简历在线制作计算机,简历在线生成,在线生成PDF或word格式简历
  16. 雷锋读图:如何通过社交媒体提高投资回报率
  17. python中的sep函数_python sep函数是什么?怎么用?
  18. 【数据结构和算法】爆肝三万字你必须知道的20个解决问题的技巧
  19. Esp32+Dht11+MQTT+Mysql实现测温数据传至数据库
  20. cs231n-2022-assignment1#Q4:Two-Layer Neural Network(Part1)

热门文章

  1. 计算机等级考试模拟题卷子,二级VB模拟试卷 1
  2. rto净化效率计算公式_全面剖析 石油化工行业RTO蓄热式焚烧炉的优势要素
  3. mysql 5.6.23免安装_mysql5.6.23免安装配置
  4. C++网络编程快速入门(二):Linux下使用select演示简单服务端程序
  5. 图像分割-基本边缘检测roberts,prewitt,sobel,canny,laplace
  6. java 批量处理 示例_Java中异常处理的示例
  7. VisualStudio运行C++项目检测include<stdio.h>报错解决方案
  8. python安全攻防---信息收集---IP查询
  9. Codeforces Global Round 13 C
  10. 电子设计大赛作品_第十四届电子设计大赛圆满结束!