如何在 iOS 上扫描条形码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/838724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I scan barcodes on iOS?
提问by Stefan
How can I simply scan barcodes on iPhone and/or iPad?
如何在 iPhone 和/或 iPad 上简单地扫描条形码?
采纳答案by Sean Owen
We produced the 'Barcodes' application for the iPhone. It can decode QR Codes. The source code is available from the zxing project; specifically, you want to take a look at the iPhone clientand the partial C++ port of the core library. The port is a little old, from circa the 0.9 release of the Java code, but should still work reasonably well.
我们为 iPhone 制作了“条形码”应用程序。它可以解码二维码。源代码可从zxing 项目获得;具体来说,你想看看iPhone客户端和核心库的部分C++端口。该端口有点旧,大约是 Java 代码的 0.9 版本,但应该仍然可以正常工作。
If you need to scan other formats, like 1D formats, you could continue the port of the Java code within this project to C++.
如果您需要扫描其他格式,如 1D 格式,您可以继续将此项目中的 Java 代码移植到 C++。
EDIT: Barcodes and the iphone
code in the project were retired around the start of 2014.
编辑:条形码和iphone
项目中的代码在 2014 年初左右退役。
回答by Vijay
回答by Alexander
As with the release of iOS7
you no longer need to use an external framework or library. The iOS ecosystem with AVFoundation now fully supports scanningalmost every code from QR over EAN to UPC.
随着发布iOS7
你不再需要使用外部框架或库。带有 AVFoundation 的 iOS 生态系统现在完全支持扫描几乎所有代码,从 EAN 上的 QR 到 UPC。
Just have a look at the Tech Noteand the AVFoundation programming guide. AVMetadataObjectTypeQRCode
is your friend.
只需查看技术说明和 AVFoundation 编程指南。AVMetadataObjectTypeQRCode
是你的朋友。
Here is a nice tutorialwhich shows it step by step: iPhone QR code scan library iOS7
这是一个很好的教程,一步一步地展示它: iPhone QR code scan library iOS7
Just a little example on how to set it up:
只是一个关于如何设置它的小例子:
#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];
}
回答by Aris Bartee
The iPhone 4 camera is more than capabale of doing barcodes. The zebra crossing barcode library has a fork on github zxing-iphone. It's open-source.
iPhone 4 摄像头不仅能处理条码。斑马线条码库在 github zxing-iphone上有一个分支。它是开源的。
回答by Josh Brown
回答by MonsieurDart
There are two major libraries:
有两个主要的库:
ZXinga library written in Java and then ported to Objective C / C++ (QR code only). And an other port to ObjC has been done, by TheLevelUp: ZXingObjC
ZBaran open source software for reading bar codes, C based.
ZXing一个用 Java 编写的库,然后移植到 Objective C/C++(仅限二维码)。TheLevelUp 已经完成了另一个 ObjC 的移植:ZXingObjC
ZBar是一种基于 C 的用于读取条码的开源软件。
According to my experiments, ZBar is far more accurate and fastthan ZXing, at least on iPhone.
根据我的实验,ZBar比 ZXing准确和快速得多,至少在 iPhone 上是这样。
回答by Suresh Varma
HOWTO: Add a barcode reader to an iPhone app, that points to ZBar iPhone SDK, looks helpful (from another thread).
如何:将条码阅读器添加到指向ZBar iPhone SDK的 iPhone 应用程序,看起来很有帮助(来自另一个线程)。
回答by abdullahselek
You can find another native iOS solution using Swift 4and Xcode 9at below. Native AVFoundation
framework used with in this solution.
您可以在下面找到另一个使用Swift 4和Xcode 9 的原生 iOS 解决方案。AVFoundation
本解决方案中使用的本机框架。
First part is the a subclass of UIViewController
which have related setup and handler functions for AVCaptureSession
.
第一部分是UIViewController
具有相关设置和处理函数的子类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)
}
}
Second part is the extension of our UIViewController
subclass for AVCaptureMetadataOutputObjectsDelegate
where we catch the captured outputs.
第二部分是我们的UIViewController
子类的扩展,用于AVCaptureMetadataOutputObjectsDelegate
捕获捕获的输出。
extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
handleCapturedOutput(metadataObjects: metadataObjects)
}
}
Update for Swift 4.2
Swift 4.2 更新
.UIApplicationWillEnterForeground
changes as UIApplication.willEnterForegroundNotification
.
.UIApplicationWillEnterForeground
更改为UIApplication.willEnterForegroundNotification
.
回答by lexx
Not sure if this will help but here is a link to an open source QR Code library. As you can see a couple of people have already used this to create apps for the iphone.
不确定这是否会有所帮助,但这里有一个指向开源QR 代码库的链接。正如您所看到的,已经有几个人使用它来为 iphone 创建应用程序。
Wikipedia has an article explaining what QR Codes are. In my opinion QR Codes are much more fit for purpose than the standard barcode where the iphone is concerned as it was designed for this type of implementation.
维基百科有一篇文章解释了什么是二维码。在我看来,QR 码比 iPhone 所关注的标准条码更适合用途,因为它是为这种类型的实现而设计的。
回答by floerkem
If support for the iPad 2 or iPod Touch is important for your application, I'd choose a barcode scanner SDK that can decode barcodes in blurry images, such as our Scandit barcode scanner SDKfor iOS and Android. Decoding blurry barcode images is also helpful on phones with autofocus cameras because the user does not have to wait for the autofocus to kick in.
如果对 iPad 2 或 iPod Touch 的支持对您的应用程序很重要,我会选择可以解码模糊图像中的条码的条码扫描器 SDK,例如适用于 iOS 和 Android 的Scandit 条码扫描器 SDK。解码模糊的条码图像在配备自动对焦摄像头的手机上也很有帮助,因为用户无需等待自动对焦启动。
Scandit comes with a free community price plan and also has a product API that makes it easy to convert barcode numbers into product names.
Scandit 附带免费的社区价格计划,还提供产品 API,可以轻松将条形码编号转换为产品名称。
(Disclaimer: I'm a co-founder of Scandit)
(免责声明:我是 Scandit 的联合创始人)