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

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

Create QRScanner.swift file

//
// 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) // 结束你的扫描动画代码
// ......
// ......
}
}

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

前往