Làm cách nào để quét mã vạch trên iOS?


189

Làm cách nào tôi có thể quét mã vạch trên iPhone và / hoặc iPad?


7
Đáng buồn thay, máy ảnh iPhone hiện đang khủng khiếp để đọc mã vạch vì ống kính của nó được lấy nét cố định thành. Tốt nhất của may mắn mặc dù!
Alastair Stuart

1
Chỉ cần giải quyết vấn đề này nên sẽ viết những quan sát của tôi. Tôi đã thử nghiệm một vài lựa chọn. RSBarcodes_Swift - dễ tích hợp, nhưng có hiệu suất rất kém. ZBarSDK - cũng dễ thực hiện, altho mất vài google tìm kiếm để tìm cách làm. Nhưng có hiệu suất thực sự tốt (không quét datamatrix và các mã hiếm khác) hoạt động thực sự tốt cho mã vạch / QRCode. Nhưng Scandit là người giỏi nhất trong số họ. Siêu nhanh, quét mọi thứ. đáng buồn là chi phí khá nhiều.
Katafalkas 2/2/2016

Câu trả lời:


82

Chúng tôi đã sản xuất ứng dụng 'Mã vạch' cho iPhone. Nó có thể giải mã mã QR. Mã nguồn có sẵn từ dự án zxing ; cụ thể, bạn muốn xem qua ứng dụng khách iPhonecổng C ++ một phần của thư viện lõi . Cổng này hơi cũ, từ bản phát hành 0,9 của mã Java, nhưng vẫn hoạt động tốt.

Nếu bạn cần quét các định dạng khác, như định dạng 1D, bạn có thể tiếp tục chuyển mã Java trong dự án này sang C ++.

EDIT: Mã vạch và iphonemã trong dự án đã nghỉ hưu vào khoảng đầu năm 2014.


Sean sử dụng loại giấy phép nào. Tôi muốn tạo một ứng dụng trả phí sử dụng Zbar. Điều đó có thể theo thỏa thuận cấp phép không?
Radu

1
Nói rõ hơn, tại thời điểm này, ZXing trên iPhone chỉ hỗ trợ Mã QR?
RefuX

Tôi tin rằng nhiều hơn đã được chuyển sang C ++, nhưng cổng vẫn là một tiếng vang thô và lỗi thời của mã Java không may. Vì vậy, có nhiều hơn được hỗ trợ mặc dù có lẽ không tốt.
Sean Owen

ZXing cho iPhone vẫn bị rò rỉ bộ nhớ 1.7 ver.
Yoon Lee

Tôi hiểu từ danh sách vấn đề trên git của zXing rằng chúng ta chỉ có thể quét mã vạch ở chế độ ngang.
Sagrian

81

Hãy xem ZBar đọc Mã QR và mã ECN / ISBN và có sẵn theo giấy phép LGPL v2.


5
Một phần đúng. ZBar.app được cấp phép theo Giấy phép Apache (Phiên bản 2.0), tuy nhiên thư viện được cấp phép theo LGPL v2.
Sean

3
Đáng buồn là giấy phép yêu cầu bạn chia sẻ tệp đối tượng của ứng dụng với bất kỳ ai yêu cầu chúng .. hãy xem zbar.sourceforge.net/iphone/sdkdoc/licensing.html
Ben Clayton

1
@BenClayton có nghĩa là gì để chia sẻ tệp đối tượng của ứng dụng?
Dejell

@Odelya Gửi các tệp .o như được tạo bởi Xcode cho bất kỳ ai, về mặt lý thuyết cho phép họ xây dựng ứng dụng của bạn. Tôi chắc chắn không hài lòng khi làm điều này (đặc biệt là cho khách hàng của mình) vì vậy ZBar không còn là câu hỏi đối với chúng tôi. Trang cấp phép ZBar đề nghị bạn chỉ nên 'hy vọng không ai yêu cầu họ!'
Ben Clayton

@BenClayton A. Cảm ơn B. Tôi có thể thay đổi thành phần nếu có ai hỏi và yêu cầu người dùng ứng dụng đã tải xuống, để tải xuống phiên bản mới hơn. Đủ chưa? C. Vậy bạn đang sử dụng thư viện nào?
Dejell

56

Như với việc phát hành, iOS7bạn không còn cần phải sử dụng một khung hoặc thư viện bên ngoài. Hệ sinh thái iOS với AVFoundation hiện hỗ trợ quét hầu hết mọi mã từ QR qua EAN đến UPC.

Chỉ cần xem qua Tech Note và hướng dẫn lập trình AVFoundation. AVMetadataObjectTypeQRCodelà bạn của bạn.

Dưới đây là một hướng dẫn hay cho thấy nó từng bước: Thư viện quét mã QR iPhone iOS7

Chỉ là một ví dụ nhỏ về cách thiết lập nó:

#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];
}

1
Nếu bạn muốn phát hiện mã vạch từ hình ảnh trên iOS8, hướng dẫn này có thể hữu ích.
Nhà phát triển NSD

Tôi thấy rằng tôi đã phải gọi startRunningvào phiên để có được mã trên để làm việc trong trường hợp giúp được bất cứ ai :)
Chris

13

Camera của iPhone 4 còn hơn cả capabale khi làm mã vạch. Thư viện mã vạch vượt qua ngựa vằn có một ngã ba trên github zxing-iphone . Đó là nguồn mở.


1
Bài đăng của bạn dường như ngụ ý rằng cổng ZXing này có thể quét nhiều hơn chỉ là Mã QR? Có phải vậy không?
RefuX

4
Cái nĩa github dường như đã chết, như được chỉ ra bởi vấn đề này: github.com/joelind/zxing-iphone/issues/3
Josh Brown

10

liteqr là "Trình đọc QR Lite trong Objective C được chuyển từ zxing" trên github và có hỗ trợ Xcode 4.


10

Có hai thư viện chính:

  • ZXing một thư viện được viết bằng Java và sau đó được chuyển sang Objective C / C ++ (chỉ mã QR). Và một cổng khác đến ObjC đã được thực hiện, bởi TheLevelUp: ZXingObjC

  • ZBar một phần mềm mã nguồn mở để đọc mã vạch, dựa trên C.

Theo thí nghiệm của tôi, ZBar chính xác và nhanh hơn nhiều so với ZXing, ít nhất là trên iPhone.


Dường như với tôi như ZXingObjC là người nên được đẩy lên hàng đầu với nhiều phiếu bầu nhất bây giờ. Tôi đã không sử dụng nó chưa , nhưng mô tả cho biết đã sẵn chẵn lẻ với ZXing 2.0.
Shaolo

Giấy phép ZBar yêu cầu bạn cung cấp các tệp đối tượng cho người dùng, vì vậy họ có thể chạy nó và cũng có thể sửa đổi thư viện của họ.
Dejell

Tôi khuyên dùng ZXingObjC
Dejell


7

Bạn có thể tìm một giải pháp iOS gốc khác bằng Swift 4Xcode 9 ở bên dưới. AVFoundationKhung bản địa được sử dụng với trong giải pháp này.

Phần đầu tiên là lớp con UIViewControllercó chức năng thiết lập và xử lý liên quan choAVCaptureSession .

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)
    }

}

Phần thứ hai là phần mở rộng của UIViewControllerlớp con của chúng tôi choAVCaptureMetadataOutputObjectsDelegate , nơi chúng tôi bắt được các kết quả đầu ra.

extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate {

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

}

Cập nhật cho Swift 4.2

.UIApplicationWillEnterForegroundthay đổi như UIApplication.willEnterForegroundNotification.


Điều này sẽ cung cấp tên sản phẩm, kích thước, giá cả, url sản phẩm, tiền tệ, tên kho? hoặc nó sẽ chỉ cung cấp số mã vạch @abdullahselek
R. Mohan

@ R.Mohan nó liên quan đến mã vạch bạn đọc. Vui lòng kiểm tra AVCaptureMetadataOutputAVMetadataMachineReadableCodeObject và thử đọc metadataObjectsbên trong hàm handleCapturedOutput .
abdullahselek

Ok, sẽ thử nó. Cảm ơn bạn đã trả lời @abdullahselek
R. Mohan

5

Không chắc chắn nếu điều này sẽ giúp nhưng đây là một liên kết đến thư viện Mã QR nguồn mở . Như bạn có thể thấy một vài người đã sử dụng điều này để tạo ứng dụng cho iphone.

Wikipedia có một bài viết giải thích Mã QR là gì . Theo tôi, Mã QR phù hợp với mục đích hơn nhiều so với mã vạch tiêu chuẩn mà iphone quan tâm vì nó được thiết kế cho loại triển khai này.


5

Nếu hỗ trợ cho iPad 2 hoặc iPod Touch là quan trọng cho ứng dụng của bạn, tôi sẽ chọn SDK máy quét mã vạch có thể giải mã mã vạch trong hình ảnh mờ, chẳng hạn như SDK máy quét mã vạch Scandit của chúng tôi cho iOS và Android. Giải mã hình ảnh mã vạch mờ cũng hữu ích trên điện thoại có camera tự động lấy nét vì người dùng không phải chờ lấy nét tự động để khởi động.

Scandit đi kèm với gói giá cộng đồng miễn phí và cũng có API sản phẩm giúp dễ dàng chuyển đổi số mã vạch thành tên sản phẩm.

(Tuyên bố miễn trừ trách nhiệm: Tôi là người đồng sáng lập của Scandit)


4

Trải nghiệm của bạn với ứng dụng này như thế nào? Đối với tôi phải mất 10 giây trở lên để giải mã mã vạch datamatrix đơn giản!
iamj4de

1
Liên kết được đổi thành stefan.hafITEDer.name / blog / 2009/09/08/19
Suresh Varma

1
Liên kết trực tiếp (Tôi không nghĩ Google sẽ biến mất điều này trong một thời gian) code.google.com/p/barcod

Có ai biết tên chính thức của ứng dụng Stefan trên cửa hàng ứng dụng là gì không? Tôi muốn tải về nó trước khi đi sâu vào mã thực tế.
macutan

3

Vấn đề với camera iPhone là các model đầu tiên (trong đó có hàng tấn đang sử dụng) có camera lấy nét cố định không thể chụp ảnh lấy nét trong khoảng cách dưới 2ft. Hình ảnh bị mờ và bị bóp méo và nếu được chụp từ khoảng cách lớn hơn thì không có đủ chi tiết / thông tin từ mã vạch.

Một số công ty đã phát triển các ứng dụng iPhone có thể hỗ trợ cho việc đó bằng cách sử dụng các công nghệ làm mờ tiên tiến. Những ứng dụng bạn có thể tìm thấy trên cửa hàng ứng dụng Apple: pic2shop, RedLaser và ShopSavvy. Tất cả các công ty đã thông báo rằng họ cũng có sẵn SDK - một số cho các điều khoản miễn phí hoặc rất ưu đãi, hãy kiểm tra xem chúng có tồn tại không.


Tôi đã thử sử dụng ShopSavvy với iphone 3G. Điều đó thật thú vị, nhưng bị treo rất thường xuyên và có một thời gian rất, rất khó đọc mã vạch phẳng, rất rõ ràng.
James Moore

1
Và tôi vừa thử pic2shop. Trích lời vị hôn thê của tôi: "điều này được cho là làm cho cuộc sống của chúng ta dễ dàng hơn thế nào?" Đây là một ứng dụng dễ thương, nhưng thực tế nó không thể đọc được mã vạch như tôi có thể nói.
James Moore

Định dạng nào bạn đã cố đọc? Tôi đã thử sử dụng pic2shop để quét EAN và nó hoạt động rất tốt. Phí giấy phép là đắt mặc dù, thậm chí nhiều hơn RedLaser.
iamj4de

2

với Swift 5 thật đơn giản và siêu nhanh !!

Bạn chỉ cần thêm vỏ ca cao "BarcodeScanner" ở đây là mã đầy đủ

source 'https://github.com/CocoaPods/Specs.git' 
platform :ios, '12.0' 
target 'Simple BarcodeScanner' 
do   
pod 'BarcodeScanner' 
end

Đảm bảo thêm quyền Camera trong tệp .plist của bạn

<key>NSCameraUsageDescription</key>
<string>Camera usage description</string>

Và thêm Trình quét và xử lý kết quả trong ViewContoder của bạn theo cách này

import UIKit
import BarcodeScanner

class ViewController: UIViewController, BarcodeScannerCodeDelegate, BarcodeScannerErrorDelegate, BarcodeScannerDismissalDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let viewController = BarcodeScannerViewController()
        viewController.codeDelegate = self
        viewController.errorDelegate = self
        viewController.dismissalDelegate = self

        present(viewController, animated: true, completion: nil)
    }

    func scanner(_ controller: BarcodeScannerViewController, didCaptureCode code: String, type: String) {
        print("Product's Bar code is :", code)
        controller.dismiss(animated: true, completion: nil)
    }

    func scanner(_ controller: BarcodeScannerViewController, didReceiveError error: Error) {
        print(error)
    }

    func scannerDidDismiss(_ controller: BarcodeScannerViewController) {
        controller.dismiss(animated: true, completion: nil)
    }
}

Tuy nhiên và bất kỳ câu hỏi hoặc thách thức, vui lòng kiểm tra ứng dụng mẫu ở đây với mã nguồn đầy đủ



1

Tôi tin rằng điều này có thể được thực hiện bằng AVFramework, đây là mã mẫu để làm điều này

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
            }
        }
    }
}

1

Đây là mã đơn giản:

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
}

1

Nếu bạn đang phát triển cho iOS> 10.2 với Swift 4 thì bạn có thể thử giải pháp của tôi. Tôi lẫn lộn nàynày hướng dẫn và đã đưa ra một ViewController mà quét một mã QR và print()nó ra. Tôi cũng có một Công tắc trong giao diện người dùng của mình để bật đèn camera, cũng có thể hữu ích. Hiện tại tôi chỉ thử nghiệm nó trên iPhone SE, vui lòng cho tôi biết nếu nó không hoạt động trên iPhone mới hơn.

Ở đây bạn đi:

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)")
        }
    }
}

0

Đôi khi nó cũng có thể hữu ích để tạo mã QR . Có một thư viện C tuyệt vời cho việc này hoạt động như một bùa mê. Nó được gọi là libqrencode . Viết một chế độ xem tùy chỉnh để hiển thị mã QR sau đó không khó và có thể được thực hiện với sự hiểu biết cơ bản về QuartzCore.


Bạn có biết bất kỳ hướng dẫn nào về cách đưa phần này vào dự án xCode của iOS không?
James

bạn có muốn chia sẻ cách bạn tạo chế độ xem bằng cách sử dụng quartcore không? sẽ là một công cụ tiết kiệm thời gian lớn: P
ThomasRS

Đúng vậy Tuy nhiên, hãy chắc chắn rằng bạn tuân thủ giấy phép phần mềm, thư viện được xuất bản cùng.
GorillaPatch

Câu hỏi này là về sự công nhận, không phải thế hệ.
MonsieurDart

0

bạn có thể kiểm tra ZBarSDK để đọc Mã QR và mã ECN / ISBN thật đơn giản để tích hợp thử mã sau đây.

- (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) {

}

và trong didFinishPickingMediaWithInfo, chúng tôi nhận được giá trị mã vạch.

    - (void) imagePickerController: (UIImagePickerController*) reader
   didFinishPickingMediaWithInfo: (NSDictionary*) info
   {
    // ADD: get the decode results
    id<NSFastEnumeration> 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];
   }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.