免费开源的iOS开发学习平台

扫描二维码

iOS7之前,开发者开发扫描二维码功能时,一般会借助第三方库,常用的如ZBarSDK等。iOS7之后,苹果官方提供的AVFoundation框架中,为我们提供了解析二维码的接口。经过测试,使用原生API扫描和处理的效率远远高于第三方库。

了解AVFoundation框架

AVFoundation框架是苹果官方提供的用于处理音频、视频的框架,其中主要包括如下的几个核心类。

  • AVCaptureSession:媒体(音、视频)捕获会话,负责把捕获的音视频数据输出到输出设备中。一个AVCaptureSession可以有多个输入输出;
  • AVCaptureDevice:输入设备,包括麦克风、摄像头,通过该类可以设置物理设备的一些属性,例如相机聚焦、白平衡等。
  • AVCaptureDeviceInput:设备输入数据管理类,可以根据AVCaptureDevice创建对应的AVCaptureDeviceInput对象,该对象将会被添加到AVCaptureSession中管理。
  • AVCaptureOutput:输出数据管理类,用于接收各类输出数据,通常使用对应的子类AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,该对象将会被添加到AVCaptureSession中管理。注意:前面几个类的对象输出数据都是NSData类型,而AVCaptureFileOutput代表数据以文件形式输出。
  • AVCaptureVideoPreviewLayer:相机拍摄预览图层,是CALayer的子类,使用该对象可以实时查看拍照或视频录制效果,创建该对象需要指定对应的AVCaptureSession对象。

二维码扫描功能实现

下方的示例代码,实现了扫描二维码功能,当程序运行后,会启动摄像头扫描二维码,并把扫描的结果打印出来。

  • 导入AVFoundation框架
#import <AVFoundation/AVFoundation.h>
  • 遵守AVCaptureMetadataOutputObjectsDelegate代理协议,并添加一个AVCaptureSession类的属性
@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic,strong) AVCaptureSession *session;
@end
  • 初始化AVCaptureSession对象的输入/输出以及其他属性
- (void)viewDidLoad {
    [super viewDidLoad];
    //获取摄像设备
    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //创建输入流
    AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    //创建输出流
    AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
    //设置代理,在主线程里刷新
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    //初始化链接对象
    self.session = [[AVCaptureSession alloc]init];
    //高质量采集率
    [self.session setSessionPreset:AVCaptureSessionPresetHigh];
    [self.session addInput:input];
    [self.session addOutput:output];
    //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
    output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
    AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
    //扫描框的位置和大小
    layer.frame = CGRectMake(60, 100, 200, 200);
    [self.view.layer insertSublayer:layer atIndex:0];
    //开始捕获
    [self.session startRunning];
}
  • 在代理方法中获取扫描到的结果
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    if (metadataObjects.count>0) {
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0 ];
        //输出扫描字符串
        NSLog(@"%@",metadataObject.stringValue);
        //停止扫描
        [self.session stopRunning];
        //跳转控制器
        WebViewController *webVC = [[WebViewController alloc] init];
        webVC.urlString = metadataObject.stringValue;
        [self.navigationController pushViewController:webVC animated:YES];
    }
}