使用AVFoundation扫描Swift 3.0中的条码或QR码

我正在按照这个教程,并试图将代码从Swift 2.0转换为3.0。 但是当我启动应用程序,该应用程序不起作用! 我的意思是,没有任何反应 这是我的代码:

视图控制器:

class ViewController: UIViewController ,BarcodeDelegate { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let barcodeViewController: BarcodeViewController = segue.destination as! BarcodeViewController barcodeViewController.delegate = self } func barcodeReaded(barcode: String) { codeTextView.text = barcode print(barcode) } } 

BarcodeVC:

 import AVFoundation protocol BarcodeDelegate { func barcodeReaded(barcode: String) } class BarcodeViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate { var delegate: BarcodeDelegate? var captureSession: AVCaptureSession! var code: String? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. print("works") self.captureSession = AVCaptureSession(); let videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) do { let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) if self.captureSession.canAddInput(videoInput) { self.captureSession.addInput(videoInput) } else { print("Could not add video input") } let metadataOutput = AVCaptureMetadataOutput() if self.captureSession.canAddOutput(metadataOutput) { self.captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code] } else { print("Could not add metadata output") } let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession) previewLayer?.frame = self.view.layer.bounds self.view.layer .addSublayer(previewLayer!) self.captureSession.startRunning() } catch let error as NSError { print("Error while creating vide input device: \(error.localizedDescription)") } } //I THINK THIS METHOD NOT CALL ! private func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { // This is the delegate'smethod that is called when a code is readed for metadata in metadataObjects { let readableObject = metadata as! AVMetadataMachineReadableCodeObject let code = readableObject.stringValue // If the code is not empty the code is ready and we call out delegate to pass the code. if code!.isEmpty { print("is empty") }else { self.captureSession.stopRunning() self.dismiss(animated: true, completion: nil) self.delegate?.barcodeReaded(barcode: code!) } } } 

这是输出:

2016-09-17 18:10:26.000919 BarcodeScaning [2610:674253] [MC] systemgroup.com.apple.configurationprofilespath的系统组容器是/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles 2016-09-17 18:10:26.007782条形码扫描[2610:674253] [MC]从公共有效的用户设置中读取。

第一步需要声明访问任何用户私人数据types,这是iOS 10中的一个新需求。您可以通过将一个用法键与一个用途string一起添加到您的应用程序的Info.plist来实现。

因为如果您正在使用以下某个框架并且无法声明使用情况,那么您的应用在首次访问时会崩溃:

联系人,日历,提醒,照片,蓝牙共享,麦克风,相机,位置,健康,HomeKit,媒体库,Motion,CallKit,语音识别,SiriKit,电视提供商。

为了避免崩溃,您需要将build议的密钥添加到Info.plist

在这里输入图像说明

然后系统在询问用户允许访问时显示目的string:

在这里输入图像说明

有关它的更多信息,你可以使用它这篇文章:

  • iOS 10中的隐私设置

我已经对BarcodeViewController进行了一些修改,使其正常工作,如下所示:

BarcodeViewController

 import UIKit import AVFoundation protocol BarcodeDelegate { func barcodeReaded(barcode: String) } class BarcodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { var delegate: BarcodeDelegate? var videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) var device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) var output = AVCaptureMetadataOutput() var previewLayer: AVCaptureVideoPreviewLayer? var captureSession = AVCaptureSession() var code: String? override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.clear self.setupCamera() } private func setupCamera() { let input = try? AVCaptureDeviceInput(device: videoCaptureDevice) if self.captureSession.canAddInput(input) { self.captureSession.addInput(input) } self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) if let videoPreviewLayer = self.previewLayer { videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill videoPreviewLayer.frame = self.view.bounds view.layer.addSublayer(videoPreviewLayer) } let metadataOutput = AVCaptureMetadataOutput() if self.captureSession.canAddOutput(metadataOutput) { self.captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code] } else { print("Could not add metadata output") } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if (captureSession.isRunning == false) { captureSession.startRunning(); } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if (captureSession.isRunning == true) { captureSession.stopRunning(); } } func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { // This is the delegate'smethod that is called when a code is readed for metadata in metadataObjects { let readableObject = metadata as! AVMetadataMachineReadableCodeObject let code = readableObject.stringValue self.dismiss(animated: true, completion: nil) self.delegate?.barcodeReaded(barcode: code!) print(code!) } } } 

其中一个要点是声明全局variables,并在viewWillAppear(:)viewWillDisappear(:)方法内启动和停止captureSession 。 在你以前的代码中,我认为它没有被调用,因为它从来没有进入处理条形码的方法。

我希望这可以帮助你。

这里是维克多·西格勒 ( Victor Sigler)的答案更新到斯威夫特4Swift 4),没有暴力,一个弱的协议和其他改进。

请注意, AVCaptureMetadataOutputObjectsDelegate的方法从

 captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) 

 metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) 

 import UIKit import AVFoundation protocol BarcodeDelegate: class { func barcodeRead(barcode: String) } class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { weak var delegate: BarcodeDelegate? var output = AVCaptureMetadataOutput() var previewLayer: AVCaptureVideoPreviewLayer! var captureSession = AVCaptureSession() override func viewDidLoad() { super.viewDidLoad() setupCamera() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if !captureSession.isRunning { captureSession.startRunning() } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if captureSession.isRunning { captureSession.stopRunning() } } private func setupCamera() { guard let device = AVCaptureDevice.default(for: .video), let input = try? AVCaptureDeviceInput(device: device) else { return } if captureSession.canAddInput(input) { captureSession.addInput(input) } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.videoGravity = .resizeAspectFill previewLayer.frame = view.bounds view.layer.addSublayer(previewLayer) let metadataOutput = AVCaptureMetadataOutput() if captureSession.canAddOutput(metadataOutput) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [.qr, .ean13] } else { print("Could not add metadata output") } } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { // This is the delegate's method that is called when a code is read for metadata in metadataObjects { if let readableObject = metadata as? AVMetadataMachineReadableCodeObject, let code = readableObject.stringValue { dismiss(animated: true) delegate?.barcodeRead(barcode: code) print(code) } } } } 

您需要将NSCameraUsageDescription添加到您的Info.plist文件才能使其正常工作!

只需在info.plist中添加一行,然后在新创build的行中键入NSCameraUsageDescription ,并添加一个string ,通知用户为什么需要在您的应用程序中访问相机。

这应该做的伎俩!

 func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { print("caught QR code") for metadata in metadataObjects { let readableObject = metadata as! AVMetadataMachineReadableCodeObject let code = readableObject.stringValue if code!.isEmpty { print("is empty") } else { self.captureSession.stopRunning() self.dismiss(animated: true, completion: nil) self.delegate?.gotQRCode(code: code!) } } } 

看起来这个方法的签名在Swift 3中有所改变。这是正确的版本