Comment puis-je scanner les codes à barres sur iOS?
11 réponses
nous avons produit l'application "codes-barres" pour l'iPhone. Il peut décoder les codes QR. Le code source est disponible à partir du ZXing project ; plus précisément, vous voulez jeter un oeil au iPhone client et le partielle C++ port of the core library . Le port est un peu vieux, de circa la version 0.9 du code Java, mais devrait quand même fonctionner assez bien.
Si vous avez besoin de scanner d'autres formats, comme les formats 1D, vous pouvez continuer le port du code Java dans ce projet vers C++.
EDIT: les codes-barres et le code iphone
dans le projet ont été retirés vers le début de 2014.
comme avec la version de iOS7
vous n'avez plus besoin d'utiliser un cadre externe ou une bibliothèque. l'écosystème iOS avec AVFoundation supporte maintenant pleinement le balayage de presque tous les codes de QR over EAN à UPC.
il suffit de jeter un oeil à la Note technique et le guide de programmation AVFoundation. AVMetadataObjectTypeQRCode
est votre ami.
Voici une belle tutoriel , qui montre étape par étape: iPhone QR code scan library iOS7
juste un petit exemple sur la façon de le configurer:
#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];
}
l'appareil photo iPhone 4 est plus que capabale de faire des codes à barres. La bibliothèque de codes à barres Zebra crossing dispose d'une fourchette sur github ZXing-iphone . Il est open-source.
liteqr est un "lecteur Lite QR dans L'objectif c porté de zxing" sur github et a le soutien pour Xcode 4.
il y a deux grandes bibliothèques:
-
ZXing une bibliothèque écrite en Java et ensuite portée à L'Objectif C / C++ (code QR seulement). Et un autre port à ObjC a été fait, par TheLevelUp: ZXingObjC
-
ZBar est un logiciel open source pour la lecture de codes à barres, C en fonction.
Selon mes expériences, ZBar est beaucoup plus précis et rapide que ZXing, au moins sur iPhone.
HOWTO: Ajouter un lecteur de code à barres à une application iPhone , qui pointe vers zbar iPhone SDK , semble utile ( à partir d'un autre fil ).
pas sûr que cela aidera, mais voici un lien vers un code source ouvert bibliothèque de Code QR . Comme vous pouvez le voir un couple de personnes ont déjà utilisé cette fonction pour créer des applications pour l'iphone.
Wikipedia a un article expliquant quels sont les codes QR . À mon avis, les codes QR sont beaucoup plus adaptés à cet usage que le code à barres standard pour l'iphone car il a été conçu pour ce type de mise en œuvre.
si la prise en charge de l'iPad 2 ou de L'iPod Touch est importante pour votre application, je choisirais un SDK scanner de code à barres qui peut décoder les codes à barres dans des images floues, comme notre scanner de code à barres Scandit SDK pour iOS et Android. Le décodage d'images de codes à barres floues est également utile sur les téléphones avec caméras autofocus car l'utilisateur n'a pas à attendre que l'autofocus se déclenche.
Scandit est livré avec un plan de prix communautaire gratuit et a également un produit API qui facilite la conversion des codes à barres en noms de produits.
(Disclaimer: je suis un des co-fondateurs de Scandit)
vous pouvez jeter un oeil à Stefan Hafeneger's iPhone DataMatrix Reader code Source ( Google Code project ; blog archivé ) si elle est encore disponible.
vous pouvez trouver une autre solution native iOS en utilisant Swift 4 et Xcode 9 ci-dessous. Cadre natif AVFoundation
utilisé dans cette solution.
la première partie est la sous-classe A de UIViewController
qui ont des fonctions de configuration et de gestion connexes pour 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)
}
}
deuxième partie est l'extension de notre UIViewController
sous-classe pour AVCaptureMetadataOutputObjectsDelegate
où nous capturons sortie.
extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
handleCapturedOutput(metadataObjects: metadataObjects)
}
}
mise à jour pour Swift 4.2
.UIApplicationWillEnterForeground
change as UIApplication.willEnterForegroundNotification
.