¿Cómo puedo escanear códigos de barras en iOS?

¿Cómo puedo simplemente escanear códigos de barras en iPhone y / o iPad?

Creamos la aplicación ‘Barcodes’ para iPhone. Puede decodificar códigos QR. El código fuente está disponible desde el proyecto zxing ; específicamente, desea echar un vistazo al cliente de iPhone y al puerto parcial de C ++ de la biblioteca central . El puerto es un poco antiguo, desde aproximadamente la versión 0.9 del código Java, pero aún debería funcionar razonablemente bien.

Si necesita escanear otros formatos, como formatos 1D, puede continuar el puerto del código Java dentro de este proyecto a C ++.

EDITAR: Los códigos de barras y el código de iphone en el proyecto fueron retirados a principios de 2014.

Verifique que ZBar lea los códigos QR y ECN / ISBN y esté disponible bajo la licencia LGPL v2.

Al igual que con el lanzamiento de iOS7 ya no es necesario utilizar un marco externo o biblioteca. El ecosistema de iOS con AVFoundation ahora es totalmente compatible con el escaneo de casi todos los códigos de QR sobre EAN a UPC.

Simplemente eche un vistazo a la Nota técnica y la guía de progtwigción AVFoundation. AVMetadataObjectTypeQRCode es tu amigo.

Aquí hay un buen tutorial que lo muestra paso a paso: Biblioteca de escaneo de códigos QR de iPhone iOS7

Solo un pequeño ejemplo de cómo configurarlo:

 #pragma mark - #pragma mark AVFoundationScanSetup - (void) setupScanner; { self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; self.session = [[AVCaptureSession alloc] init]; self.output = [[AVCaptureMetadataOutput alloc] init]; [self.session addOutput:self.output]; [self.session addInput:self.input]; [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode]; self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill; self.preview.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); AVCaptureConnection *con = self.preview.connection; con.videoOrientation = AVCaptureVideoOrientationLandscapeLeft; [self.view.layer insertSublayer:self.preview atIndex:0]; } 

La cámara iPhone 4 es más que capabale de hacer códigos de barras. La biblioteca de código de barras de paso de cebra tiene un tenedor en github zxing-iphone . Es de código abierto.

liteqr es un “Lite QR Reader en Objective C portado desde zxing” en github y tiene soporte para Xcode 4.

Hay dos bibliotecas principales:

  • ZXing una biblioteca escrita en Java y luego portada a Objective C / C ++ (solo código QR). Y otro puerto para ObjC ha sido hecho por TheLevelUp: ZXingObjC

  • ZBar es un software de código abierto para leer códigos de barras, basado en C.

De acuerdo con mis experimentos, ZBar es mucho más preciso y rápido que ZXing, al menos en iPhone.

CÓMO: Agregar un lector de código de barras a una aplicación de iPhone , que apunte a ZBar iPhone SDK , parece útil ( de otro hilo ).

No estoy seguro si esto ayudará, pero aquí hay un enlace a una biblioteca de códigos QR de código abierto. Como puede ver, un par de personas ya han usado esto para crear aplicaciones para el iphone.

Wikipedia tiene un artículo explicando qué códigos QR son . En mi opinión, los códigos QR son mucho más adecuados para el propósito que el código de barras estándar en lo que respecta al iPhone, ya que fue diseñado para este tipo de implementación.

Si la compatibilidad con el iPad 2 o iPod Touch es importante para su aplicación, elegiría un SDK de escáner de código de barras que pueda decodificar códigos de barras en imágenes borrosas, como nuestro SDK de escáner de códigos de barras Scandit para iOS y Android. La deencoding de imágenes de códigos de barras borrosas también es útil en teléfonos con cámaras de enfoque automático porque el usuario no tiene que esperar a que el enfoque automático se active.

Scandit viene con un plan de precios para la comunidad gratuito y también tiene una API de productos que facilita la conversión de números de códigos de barras en nombres de productos.

(Descargo de responsabilidad: soy cofundador de Scandit)

Podrías echarle un vistazo al código fuente del lector de datos DataMatrix iPhone de Stefan Hafeneger ( proyecto de código de Google , publicación de blog archivada ) si todavía está disponible.

El problema con la cámara de iPhone es que los primeros modelos (de los cuales hay toneladas en uso) tienen una cámara de foco fijo que no puede tomar imágenes enfocadas para distancias menores de 2 pies. Las imágenes son borrosas y distorsionadas y, si se toman desde una distancia mayor, no hay suficientes detalles / información del código de barras.

Algunas compañías han desarrollado aplicaciones para iPhone que pueden adaptarse a eso mediante el uso de tecnologías avanzadas de desenfoque. Esas aplicaciones que puedes encontrar en la tienda de aplicaciones de Apple: pic2shop, RedLaser y ShopSavvy. Todas las empresas han anunciado que también tienen SDK disponibles, algunos de forma gratuita o muy preferencial, verifique uno.

Puede encontrar otra solución nativa de iOS usando Swift 4 y Xcode 9 a continuación. Marco de AVFoundation nativo utilizado en esta solución.

La primera parte es la subclase de UIViewController que tiene funciones relacionadas de configuración y manejo para AVCaptureSession .

 import UIKit import AVFoundation class BarCodeScannerViewController: UIViewController { let captureSession = AVCaptureSession() var videoPreviewLayer: AVCaptureVideoPreviewLayer! var initialized = false let barCodeTypes = [AVMetadataObject.ObjectType.upce, AVMetadataObject.ObjectType.code39, AVMetadataObject.ObjectType.code39Mod43, AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.code128, AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.aztec, AVMetadataObject.ObjectType.pdf417, AVMetadataObject.ObjectType.itf14, AVMetadataObject.ObjectType.dataMatrix, AVMetadataObject.ObjectType.interleaved2of5, AVMetadataObject.ObjectType.qr] override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) setupCapture() // set observer for UIApplicationWillEnterForeground, so we know when to start the capture session again NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // this view is no longer topmost in the app, so we don't need a callback if we return to the app. NotificationCenter.default.removeObserver(self, name: .UIApplicationWillEnterForeground, object: nil) } // This is called when we return from another app to the scanner view @objc func willEnterForeground() { setupCapture() } func setupCapture() { var success = false var accessDenied = false var accessRequested = false let authorizationStatus = AVCaptureDevice.authorizationStatus(for: .video) if authorizationStatus == .notDetermined { // permission dialog not yet presented, request authorization accessRequested = true AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted:Bool) -> Void in self.setupCapture(); }) return } if authorizationStatus == .restricted || authorizationStatus == .denied { accessDenied = true } if initialized { success = true } else { let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInTelephotoCamera, .builtInDualCamera], mediaType: .video, position: .unspecified) if let captureDevice = deviceDiscoverySession.devices.first { do { let videoInput = try AVCaptureDeviceInput(device: captureDevice) captureSession.addInput(videoInput) success = true } catch { NSLog("Cannot construct capture device input") } } else { NSLog("Cannot get capture device") } } if success { DispatchQueue.global().async { self.captureSession.startRunning() DispatchQueue.main.async { let captureMetadataOutput = AVCaptureMetadataOutput() self.captureSession.addOutput(captureMetadataOutput) let newSerialQueue = DispatchQueue(label: "barCodeScannerQueue") // in iOS 11 you can use main queue captureMetadataOutput.setMetadataObjectsDelegate(self, queue: newSerialQueue) captureMetadataOutput.metadataObjectTypes = self.barCodeTypes self.videoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession) self.videoPreviewLayer.videoGravity = .resizeAspectFill self.videoPreviewLayer.frame = self.view.layer.bounds self.view.layer.addSublayer(self.videoPreviewLayer) } } initialized = true } else { // Only show a dialog if we have not just asked the user for permission to use the camera. Asking permission // sends its own dialog to th user if !accessRequested { // Generic message if we cannot figure out why we cannot establish a camera session var message = "Cannot access camera to scan bar codes" #if (arch(i386) || arch(x86_64)) && (!os(macOS)) message = "You are running on the simulator, which does not hae a camera device. Try this on a real iOS device." #endif if accessDenied { message = "You have denied this app permission to access to the camera. Please go to settings and enable camera access permission to be able to scan bar codes" } let alertPrompt = UIAlertController(title: "Cannot access camera", message: message, preferredStyle: .alert) let confirmAction = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in self.navigationController?.popViewController(animated: true) }) alertPrompt.addAction(confirmAction) self.present(alertPrompt, animated: true, completion: nil) } } } func handleCapturedOutput(metadataObjects: [AVMetadataObject]) { if metadataObjects.count == 0 { return } guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject else { return } if barCodeTypes.contains(metadataObject.type) { if let metaDataString = metadataObject.stringValue { captureSession.stopRunning() displayResult(code: metaDataString) return } } } func displayResult(code: String) { let alertPrompt = UIAlertController(title: "Bar code detected", message: code, preferredStyle: .alert) if let url = URL(string: code) { let confirmAction = UIAlertAction(title: "Launch URL", style: .default, handler: { (action) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: { (result) in if result { NSLog("opened url") } else { let alertPrompt = UIAlertController(title: "Cannot open url", message: nil, preferredStyle: .alert) let confirmAction = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in }) alertPrompt.addAction(confirmAction) self.present(alertPrompt, animated: true, completion: { self.setupCapture() }) } }) }) alertPrompt.addAction(confirmAction) } let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in self.setupCapture() }) alertPrompt.addAction(cancelAction) present(alertPrompt, animated: true, completion: nil) } } 

La segunda parte es la extensión de nuestra subclase AVCaptureMetadataOutputObjectsDelegate para AVCaptureMetadataOutputObjectsDelegate donde AVCaptureMetadataOutputObjectsDelegate los resultados capturados.

 extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { handleCapturedOutput(metadataObjects: metadataObjects) } } 

Para un escáner de código de barras iOS 7 nativo, eche un vistazo a mi proyecto en GitHub:

https://github.com/werner77/WECodeScanner

Aquí hay un código simple:

 func scanbarcode() { view.backgroundColor = UIColor.blackColor() captureSession = AVCaptureSession() let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) let videoInput: AVCaptureDeviceInput do { videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) } catch { return } if (captureSession.canAddInput(videoInput)) { captureSession.addInput(videoInput) } else { failed(); return; } let metadataOutput = AVCaptureMetadataOutput() if (captureSession.canAddOutput(metadataOutput)) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code] } else { failed() return } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession); previewLayer.frame = view.layer.bounds; previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; view.layer.addSublayer(previewLayer); view.addSubview(closeBtn) view.addSubview(backimg) captureSession.startRunning(); } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func failed() { let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .Alert) ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) presentViewController(ac, animated: true, completion: nil) captureSession = nil } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) if (captureSession?.running == false) { captureSession.startRunning(); } } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) if (captureSession?.running == true) { captureSession.stopRunning(); } } func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { captureSession.stopRunning() if let metadataObject = metadataObjects.first { let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject; AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) foundCode(readableObject.stringValue); } // dismissViewControllerAnimated(true, completion: nil) } func foundCode(code: String) { var createAccountErrorAlert: UIAlertView = UIAlertView() createAccountErrorAlert.delegate = self createAccountErrorAlert.title = "Alert" createAccountErrorAlert.message = code createAccountErrorAlert.addButtonWithTitle("ok") createAccountErrorAlert.addButtonWithTitle("Retry") createAccountErrorAlert.show() NSUserDefaults.standardUserDefaults().setObject(code, forKey: "barcode") NSUserDefaults.standardUserDefaults().synchronize() ItemBarcode = code print(code) } override func prefersStatusBarHidden() -> Bool { return true } override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return .Portrait } 

A veces puede ser útil también para generar códigos QR . Hay una excelente biblioteca de C para esto que funciona como un encanto. Se llama libqrencode . Escribir una vista personalizada para mostrar el código QR no es tan difícil y se puede hacer con una comprensión básica de QuartzCore.

puede verificar ZBarSDK para leer el código QR y los códigos ECN / ISBN, es fácil de integrar intente con el siguiente código.

 - (void)scanBarcodeWithZBarScanner { // ADD: present a barcode reader that scans from the camera feed ZBarReaderViewController *reader = [ZBarReaderViewController new]; reader.readerDelegate = self; reader.supportedOrientationsMask = ZBarOrientationMaskAll; ZBarImageScanner *scanner = reader.scanner; // TODO: (optional) additional reader configuration here // EXAMPLE: disable rarely used I2/5 to improve performance [scanner setSymbology: ZBAR_I25 config: ZBAR_CFG_ENABLE to: 0]; //Get the return value from controller [reader setReturnBlock:^(BOOL value) { } 

y en didFinishPickingMediaWithInfo obtenemos el valor del código de barras.

  - (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info { // ADD: get the decode results id results = [info objectForKey: ZBarReaderControllerResults]; ZBarSymbol *symbol = nil; for(symbol in results) // EXAMPLE: just grab the first barcode break; // EXAMPLE: do something useful with the barcode data barcodeValue = symbol.data; // EXAMPLE: do something useful with the barcode image barcodeImage = [info objectForKey:UIImagePickerControllerOriginalImage]; [_barcodeIV setImage:barcodeImage]; //set the values for to TextFields [self setBarcodeValue:YES]; // ADD: dismiss the controller (NB dismiss from the *reader*!) [reader dismissViewControllerAnimated:YES completion:nil]; } 

Creo que esto se puede hacer usando AVFramework, aquí está el código de muestra para hacer esto

 import UIKit import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { @IBOutlet weak var lblQRCodeResult: UILabel! @IBOutlet weak var lblQRCodeLabel: UILabel! var objCaptureSession:AVCaptureSession? var objCaptureVideoPreviewLayer:AVCaptureVideoPreviewLayer? var vwQRCode:UIView? override func viewDidLoad() { super.viewDidLoad() self.configureVideoCapture() self.addVideoPreviewLayer() self.initializeQRView() } func configureVideoCapture() { let objCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) var error:NSError? let objCaptureDeviceInput: AnyObject! do { objCaptureDeviceInput = try AVCaptureDeviceInput(device: objCaptureDevice) as AVCaptureDeviceInput } catch let error1 as NSError { error = error1 objCaptureDeviceInput = nil } objCaptureSession = AVCaptureSession() objCaptureSession?.addInput(objCaptureDeviceInput as! AVCaptureInput) let objCaptureMetadataOutput = AVCaptureMetadataOutput() objCaptureSession?.addOutput(objCaptureMetadataOutput) objCaptureMetadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) objCaptureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] } func addVideoPreviewLayer() { objCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: objCaptureSession) objCaptureVideoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill objCaptureVideoPreviewLayer?.frame = view.layer.bounds self.view.layer.addSublayer(objCaptureVideoPreviewLayer!) objCaptureSession?.startRunning() self.view.bringSubviewToFront(lblQRCodeResult) self.view.bringSubviewToFront(lblQRCodeLabel) } func initializeQRView() { vwQRCode = UIView() vwQRCode?.layer.borderColor = UIColor.redColor().CGColor vwQRCode?.layer.borderWidth = 5 self.view.addSubview(vwQRCode!) self.view.bringSubviewToFront(vwQRCode!) } func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { if metadataObjects == nil || metadataObjects.count == 0 { vwQRCode?.frame = CGRectZero lblQRCodeResult.text = "QR Code wans't found" return } let objMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if objMetadataMachineReadableCodeObject.type == AVMetadataObjectTypeQRCode { let objBarCode = objCaptureVideoPreviewLayer?.transformedMetadataObjectForMetadataObject(objMetadataMachineReadableCodeObject as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject vwQRCode?.frame = objBarCode.bounds; if objMetadataMachineReadableCodeObject.stringValue != nil { lblQRCodeResult.text = objMetadataMachineReadableCodeObject.stringValue } } } } 

si está desarrollando para iOS> 10.2 con Swift 4, entonces puede probar mi solución. Combiné esto y este tutorial y se me ocurrió un ViewController que escanea un código QR e print() . También tengo un interruptor en mi UI para alternar la luz de la cámara, también podría ser útil. Por ahora solo lo probé en un iPhone SE, por favor avíseme si no funciona en iPhones más nuevos.

Aqui tienes:

 import UIKit import AVFoundation class QRCodeScanner: UIViewController, AVCaptureMetadataOutputObjectsDelegate { let captureSession: AVCaptureSession = AVCaptureSession() var videoPreviewLayer: AVCaptureVideoPreviewLayer? let qrCodeFrameView: UIView = UIView() var captureDevice: AVCaptureDevice? override func viewDidLoad() { // Get the back-facing camera for capturing videos let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDualCamera], mediaType: AVMediaType.video, position: .back) captureDevice = deviceDiscoverySession.devices.first if captureDevice == nil { print("Failed to get the camera device") return } do { // Get an instance of the AVCaptureDeviceInput class using the previous device object. let input = try AVCaptureDeviceInput(device: captureDevice!) // Set the input device on the capture session. captureSession.addInput(input) // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. let captureMetadataOutput = AVCaptureMetadataOutput() captureSession.addOutput(captureMetadataOutput) // Set delegate and use the default dispatch queue to execute the call back captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer. videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) if let videoPreviewLayer = videoPreviewLayer { videoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill videoPreviewLayer.frame = view.layer.bounds view.layer.addSublayer(videoPreviewLayer) // Start video capture. captureSession.startRunning() if let hasFlash = captureDevice?.hasFlash, let hasTorch = captureDevice?.hasTorch { if hasFlash && hasTorch { view.bringSubview(toFront: bottomBar) try captureDevice?.lockForConfiguration() } } } // QR Code Overlay qrCodeFrameView.layer.borderColor = UIColor.green.cgColor qrCodeFrameView.layer.borderWidth = 2 view.addSubview(qrCodeFrameView) view.bringSubview(toFront: qrCodeFrameView) } catch { // If any error occurs, simply print it out and don't continue any more. print("Error: \(error)") return } } // MARK: Buttons and Switch @IBAction func switchFlashChanged(_ sender: UISwitch) { do { if sender.isOn { captureDevice?.torchMode = .on } else { captureDevice?.torchMode = .off } } } // MARK: AVCaptureMetadataOutputObjectsDelegate func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { // Check if the metadataObjects array is not nil and it contains at least one object. if metadataObjects.count == 0 { qrCodeFrameView.frame = CGRect.zero return } // Get the metadata object. let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if metadataObj.type == AVMetadataObject.ObjectType.qr { // If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) qrCodeFrameView.frame = barCodeObject!.bounds print("QR Code: \(metadataObj.stringValue)") } } } 

Saludos, Paul