iOS - QRCode 二维码

1、QRCode

  • 在 iOS7 以前,在 iOS 中实现二维码和条形码扫描,我们所知的有,两大开源组件 ZBar 与 ZXing。iOS7 之后可以利用系统原生 API 生成二维码, iOS8 之后可以生成条形码, 系统默认生成的颜色是黑色。

    • 1、ZBar 在扫描的灵敏度上,和内存的使用上相对于 ZXing 上都是较优的,但是对于 “圆角二维码” 的扫描确很困难。
    • 2、ZXing 是 Google Code 上的一个开源的条形码扫描库,是用 java 设计的,连 Google Glass 都在使用的。但有人为了追求更高效率以及可移植性,出现了 c++ port。Github 上的 Objectivc-C port,其实就是用 OC 代码封装了一下而已,而且已经停止维护。这样效率非常低,在 instrument 下面可以看到 CPU 和内存疯涨,在内存小的机器上很容易崩溃。
    • 3、AVFoundation 无论在扫描灵敏度和性能上来说都是最优的,所以毫无疑问我们应该切换到 AVFoundation,需要兼容 iOS 6 或之前的版本可以用 ZBar 或 ZXing 代替。
  • 在 iOS8 + 系统中使用相机需要在 Info.plist 中添加 Privacy - Camera Usage Description,并设置其值。使用相册需要在 Info.plist 中添加 Privacy - Photo Library Usage Description,并设置其值。

    QRCode24

  • 按照下图在 Info.plist 文件中将 Localization native development region 的值改为 China。如果不设置此项弹出的相册页面中显示的按钮等为英文菜单。

    QRCode25

2、系统原生二维码

2.1 扫描二维码

  • 官方提供的接口非常简单,直接看代码,主要使用的是 AVFoundation。

        // 包含头文件
        #import <AVFoundation/AVFoundation.h>
    
        // 遵守协议
        <AVCaptureMetadataOutputObjectsDelegate>
    
        // 输入输出的中间桥梁
        @property (nonatomic, strong) AVCaptureSession *session;
    
        // 扫描窗口
        @property (nonatomic, strong) UIImageView *scanView;
    
        // 创建扫描视图窗口,自定义方法
        - (void)createdScanView {
    
            CGFloat margin = 50;
            CGRect scanFrame = CGRectMake(margin,
                                          margin + 20,
                                          self.view.bounds.size.width - margin * 2,
                                          self.view.bounds.size.width - margin * 2);
    
            self.scanView = [[UIImageView alloc] initWithFrame:scanFrame];
    
            self.scanView.image = [UIImage imageNamed:@"scan_bg2"];
    
            [self.view addSubview:self.scanView];
    
            // 创建扫描
            [self startScan];
        }
    
        // 创建扫描,自定义方法
        - (void)startScan {
    
            // 获取摄像设备
            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()];
    
            // 设置有效扫描区域
            output.rectOfInterest = [self getScanCropWithScanViewFrame:self.scanView.frame readerViewBounds:self.view.bounds];
    
            // 初始化链接对象
            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 = self.view.layer.bounds;
            [self.view.layer insertSublayer:layer atIndex:0];
    
            // 开始捕获
            [self.session startRunning];
        }
    
        // 设置扫描区域的比例关系,自定义方法
        - (CGRect)getScanCropWithScanViewFrame:(CGRect)scanViewFrame readerViewBounds:(CGRect)readerViewBounds {
    
            CGFloat x, y, width, height;
    
            x = scanViewFrame.origin.y / readerViewBounds.size.height;
            y = scanViewFrame.origin.x / readerViewBounds.size.width;
            width = scanViewFrame.size.height / readerViewBounds.size.height;
            height = scanViewFrame.size.width / readerViewBounds.size.width;
    
            return CGRectMake(x, y, width, height);
        }
    
        // 获取扫描结果,AVCaptureMetadataOutputObjectsDelegate 协议方法
        - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
                                                                         fromConnection:(AVCaptureConnection *)connection {
    
            if (metadataObjects.count > 0) {
    
                // 停止扫描
                [self.session stopRunning];
    
                AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
    
                // 获取扫描结果
                NSString *resultString = metadataObject.stringValue;
    
                // 输出扫描字符串
                [[[UIAlertView alloc] initWithTitle:@"扫描成功"
                                            message:resultString
                                           delegate:nil
                                  cancelButtonTitle:@"确定"
                                  otherButtonTitles:nil] show];
            }
        }
  • 一些初始化的代码加上实现代理方法便完成了二维码扫描的工作,这里我们需要注意的是,在二维码扫描的时候,我们一般都会在屏幕中间放一个方框,用来显示二维码扫描的大小区间,这里我们在AVCaptureMetadataOutput 类中有一个 rectOfInterest 属性,它的作用就是设置扫描范围。这个 CGRect 参数和普通的 Rect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值