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

Create QRScanner.swiftfile

//
//  QRScanner.swift
//  NativeQR
//
//  Created by Harvey on 2017/10/24.
//  Copyright © 2017年 Harvey. All rights reserved.
//

import Foundation
import AVFoundation
import UIKit

class QRScanner: NSObject {
    
    static let shared = QRScanner()
    
    private let captureSession = AVCaptureSession()
    private let videoPreviewLayer = AVCaptureVideoPreviewLayer()
    
    private var handleCompleted: ((String) -> ())? = nil
    
    private override init() {
        
        super.init()
        
        AVCaptureDevice.requestAccess(for: AVMediaType.video) { (isSuccess) in
        
            if isSuccess {
                
                self.prepare()
            }else {
                
                print("无权访问摄像机")
            }
        }
    }
    
    private func prepare() {
        
        guard let device = AVCaptureDevice.default(for: .video) else {
        
            print("获取摄像设备发生错误")
            return
        }
        
        guard let deviceInput = try? AVCaptureDeviceInput(device: device) else {
            
            print("创建设备输入流发生错误")
            return
        }
        
        // 创建数据输出流
        let metadataOutput = AVCaptureMetadataOutput()
        metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        
        // 创建设备输出流
        let videoDataOutput = AVCaptureVideoDataOutput()
        videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
        
        // 会话采集率: AVCaptureSessionPresetHigh
        captureSession.sessionPreset = .high
        
        // 添加数据输出流到会话对象
        captureSession.addOutput(metadataOutput)
        
        // 添加设备输出流到会话对象
        captureSession.addOutput(videoDataOutput)
      
        // 添加设备输入流到会话对象
        captureSession.addInput(deviceInput)
        
        // 设置数据输出类型
        metadataOutput.metadataObjectTypes = [
            .qr,        // 二维码
            .ean13,     // 条形码
            .ean8,      // 条形码
            .code128    // 条形码
        ]
        
        videoPreviewLayer.session = captureSession
        videoPreviewLayer.videoGravity = .resizeAspectFill
    }
    
    func scan(design: @escaping (_ previewLayer: CALayer)->()) -> Self {
        
        design(videoPreviewLayer)
        
        startRunning()
        
        return self
    }
    
    func completed(aCompleted: @escaping (_ value: String)->()) {
        
        self.handleCompleted = aCompleted
    }
    
    func startRunning() {
        
        captureSession.startRunning()
    }
    
    func stopRunning() {
        
        captureSession.stopRunning()
    }
}

extension QRScanner: AVCaptureMetadataOutputObjectsDelegate {
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        
        guard metadataObjects.count>0 else{
            
            return
        }
        
        stopRunning()
        
        guard let stringValue = metadataObjects.first!.value(forKey: "stringValue") as? String else {
            
            return
        }
        
        handleCompleted?(stringValue)
    }
}

extension QRScanner: AVCaptureVideoDataOutputSampleBufferDelegate {
    
    func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        
    }
}

使用示例

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    QRScanner.shared
    .scan { (previewLayer) in
        
        /// 设置preview的frame
        let width = UIScreen.main.bounds.size.width - 100
        previewLayer.frame = CGRect(x: 50, y: 100, width: width, height: width)
        self.view.layer.insertSublayer(previewLayer, at: 0)
        
        // 你的扫描动画代码
        // ......
        // ......
    }
    .completed { (qrValue) in // 处理二维码
        
         print(qrValue)
        
        // 结束你的扫描动画代码
        // ......
        // ......
    }
}

代码及示例下载(有实现生成二维码)
前往

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Harvey66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值