原文:http://strivingboy.github.io/blog/2014/11/08/scan-qrcode/

关于二维码扫描有不少优秀第三方库如:

最近项目需要,看了下使用ios7自带的 AVFoundation Framework 来实现二维码扫描,Demo 见:scan_qrcode_demo

关于AVFoundation

AVFoundation 是一个很大基础库,用来创建基于时间的视听媒体,可以使用它来检查,创建、编辑或媒体文件。也可以输入流从设备和操作视频实时捕捉和回放。详细框架介绍见官网:About AV Foundation,本文只是介绍如果使用AVFoundation获取二维码。

首先获取流媒体信息我们需要AVCaptureSession对象来管理输入流和输出流,AVCaptureVideoPreviewLayer对象来显示信息,基本流程如下图所示:

注:

  • AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
  • AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
  • AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
  • AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
  • AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。

下面看下实现过程如下:

Step1:需要导入:AVFoundation Framework 包含头文件:

#import <AVFoundation/AVFoundation.h>

Step2:设置捕获会话

设置 AVCaptureSession 和 AVCaptureVideoPreviewLayer 成员

1
2
3
4
5
6
7
8
9
10
    #import <AVFoundation/AVFoundation.h>

    static const char *kScanQRCodeQueueName = "ScanQRCodeQueue";

    @interface ViewController () <AVCaptureMetadataOutputObjectsDelegate>
.....
@property (nonatomic) AVCaptureSession *captureSession;
@property (nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (nonatomic) BOOL lastResult;
@end

Step3:创建会话,读取输入流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    - (BOOL)startReading
{
// 获取 AVCaptureDevice 实例
NSError * error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 初始化输入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@", [error localizedDescription]);
return NO;
}
// 创建会话
_captureSession = [[AVCaptureSession alloc] init];
// 添加输入流
[_captureSession addInput:input];
// 初始化输出流
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
// 添加输出流
[_captureSession addOutput:captureMetadataOutput]; // 创建dispatch queue.
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
// 设置元数据类型 AVMetadataObjectTypeQRCode
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]]; // 创建输出对象
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:_sanFrameView.layer.bounds];
[_sanFrameView.layer addSublayer:_videoPreviewLayer];
// 开始会话
[_captureSession startRunning]; return YES;
}

Step4:停止读取

1
2
3
4
5
6
7
    - (void)stopReading
{
// 停止会话
[_captureSession stopRunning];
_captureSession = nil;
}

Step5:获取捕获数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
fromConnection:(AVCaptureConnection *)connection
{
if (metadataObjects != nil && [metadataObjects count] > 0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
NSString *result;
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
result = metadataObj.stringValue;
} else {
NSLog(@"不是二维码");
}
[self performSelectorOnMainThread:@selector(reportScanResult:) withObject:result waitUntilDone:NO];
}
}

Step6:处理结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  - (void)reportScanResult:(NSString *)result
{
[self stopReading];
if (!_lastResult) {
return;
}
_lastResut = NO;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"二维码扫描"
message:result
delegate:nil
cancelButtonTitle:@"取消"
otherButtonTitles: nil];
[alert show];
// 以下处理了结果,继续下次扫描
_lastResult = YES;
}

以上基本就是二维码的获取流程,和扫一扫二维码伴随的就是开启系统照明,这个比较简单,也是利用 AVCaptureDevice,请看如下实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
  - (void)systemLightSwitch:(BOOL)open
{
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([device hasTorch]) {
[device lockForConfiguration:nil];
if (open) {
[device setTorchMode:AVCaptureTorchModeOn];
} else {
[device setTorchMode:AVCaptureTorchModeOff];
}
[device unlockForConfiguration];
}
}

以上就是本文介绍的大部分内容,详细代码请看demo scan_qrcode_deomo

实现过程中遇到一下两个问题:

1、扫描一个二维码,输出流回重复调用,代理方法头文件介绍:

1
2
3
4
5
6
7
8
9
10
11
12
13
   /*!
@method captureOutput:didOutputMetadataObjects:fromConnection:
.....
@discussion
Delegates receive this message whenever the output captures and emits new objects, as specified by
its metadataObjectTypes property. Delegates can use the provided objects in conjunction with other APIs
for further processing. This method will be called on the dispatch queue specified by the output's
metadataObjectsCallbackQueue property. **This method may be called frequently** so it must be efficient to
prevent capture performance problems, including dropped metadata objects. Clients that need to reference metadata objects outside of the scope of this method must retain them and
then release them when they are finished with them.
*/

代理方法会频繁调用,我暂且用一个标记(@property (nonatomic) BOOL lastResult)表示是否是第一次扫描成功,来处理。

2、AVFoundation 该库不能扫描相册中的二维码图片,不知为啥苹果没有支持,有知道实现的麻烦告诉我哈。

参考链接

【转】 iOS使用AVFoundation实现二维码扫描的更多相关文章

  1. iOS使用AVFoundation实现二维码扫描(ios7以上)——转载

    关于二维码扫描有不少优秀第三方库: ZBar SDK 里面有详细的文档,相应介绍也非常多,如:http://rdcworld-iphone.blogspot.in/2013/03/how-to-use ...

  2. iOS使用AVFoundation实现二维码扫描

    原文:http://strivingboy.github.io/blog/2014/11/08/scan-qrcode/ 关于二维码扫描有不少优秀第三方库如: ZBar SDK 里面有详细的文档,相应 ...

  3. Swift:使用系统AVFoundation实现二维码扫描和生成

    系统提供的AVCaptureSession仅仅适用于iOS7.0以上的系统.之前的请用Zbar来替代 下载地址:http://download.csdn.net/detail/huobanbengku ...

  4. iOS 原生库(AVFoundation)实现二维码扫描,封装的工具类,不依赖第三方库,可高度自定义扫描动画及界面(Swift 4.0)

    Create QRScanner.swift file // // QRScanner.swift // NativeQR // // Created by Harvey on 2017/10/24. ...

  5. iOS学习——iOS原生实现二维码扫描

    最近项目上需要开发扫描二维码进行签到的功能,主要用于开会签到的场景,所以为了避免作弊,我们再开发时只采用直接扫描的方式,并且要屏蔽从相册读取图片,此外还在二维码扫描成功签到时后台会自动上传用户的当前地 ...

  6. Ios二维码扫描(系统自带的二维码扫描)

    Ios二维码扫描 这里给大家介绍的时如何使用系统自带的二维码扫描方法和一些简单的动画! 操作步骤: 1).首先你需要搭建UI界面如图:下图我用了俩个imageview和一个label 2).你需要在你 ...

  7. iOS二维码扫描IOS7系统实现

    扫描相关类 二维码扫描需要获取摄像头并读取照片信息,因此我们需要导入系统的AVFoundation框架,创建视频会话.我们需要用到一下几个类: AVCaptureSession 会话对象.此类作为硬件 ...

  8. iOS - 二维码扫描和应用跳转

    序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦, ...

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

    iOS开发-二维码扫描和应用跳转   序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如Z ...

随机推荐

  1. codeforces C. Restore Graph

    题意:构造一个有n个顶点,每个点度不超过k,然后给出每一个点到达一个定点的最短距离d数组,然后构造出这样的一个图: 思路:排序之后,有两个距离为0的或者没有直接输出-1,然后用两个游动下表,后面的与前 ...

  2. cf C. Arithmetic Progression

    http://codeforces.com/contest/382/problem/C 题意:给你n个数,然后让你添加一个数使得n+1个数能形成这样的规律,a[1]-a[0]=a[2]-a[1]=a[ ...

  3. 可重入与线程安全(大多数Qt类是可重入,非线程安全的)

    可重入与线程安全 在Qt文档中,术语“可重入”与“线程安全”被用来说明一个函数如何用于多线程程序.假如一个类的任何函数在此类的多个不同的实例上,可以被多个线程同时调用,那么这个类被称为是“可重入”的. ...

  4. Android Wear开发 - 卡片通知 - 第二节 : 自定义Wear卡片样式

    一.前言说明 在上一节添加Android Wear通知特性我们实现了简单的Android Wear卡片拓展,但是默认提供给我们的多张卡片只能实现简单的文字展示,如果想要自定义布局,添加图片等等,则需要 ...

  5. Lucky and Good Months by Gregorian Calendar(模拟)

    http://poj.org/problem?id=3393 好大的一道模拟题,直接当阅读理解看了.下面是大神写的题意,解释的好详细. 定义: Goog month : 该月第一个工作日为星期一的月份 ...

  6. C#导出数据的EXCEL模板设计

    一:将如下图中,查询出来的数据导出到EXCEL中 二:Excel的状态 三:设计的背后工作 四:最后一步,隐藏

  7. .net core4

  8. A_star poj2449 k短路

    赛后填坑系列QAQ 贴代码呀 #include<iostream> #include<algorithm> #include<cstdio> #include< ...

  9. Python爬虫获取迅雷会员帐号

    代码如下: import re import urllib.request import urllib import time from collections import deque head = ...

  10. jQuery EasyUI动态添加控件或者ajax加载页面后不能自动渲染问题的解决方法

    博客分类: jquery-easyui jQueryAjax框架HTML  现象: AJAX返回的html无法做到自动渲染为EasyUI的样式.比如:class="easyui-layout ...