Search code examples
swiftbarcode-scanner

Swift: Unable to detect linear type Barcodes


I am writing a barcode reader app but I am unable to detect linear type barcodes, ie code 128. I have no issues with Qr codes, EAN13 types and ISBN types. My code is pretty straightforward:

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

        if metadataObjects.count != 0 {
            if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
                if object.type == AVMetadataObject.ObjectType.qr {
                    if let text = object.stringValue {
                        print(text)

                        session.stopRunning()

                        let alertVC = UIAlertController(title: "QR Code", message: text, preferredStyle: UIAlertControllerStyle.alert)
                        alertVC.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
                            self.session.startRunning()
                        }))
                        present(alertVC, animated: true, completion: nil)
                    }
                } else {
                    if let text = object.stringValue {
                        print("Other code detected: ", text)
                    }
                }
            }
        }

I used this free online barcode generator to test my app. I am able to detect most of other barcodes, except Linear Codes. Has anyone encountered such problems too?


Solution

  • Make sure to include AVMetadataObjectTypeCode128Code [.code128] when setting AVCaptureMetadataOutput object types metadataObjectTypes.

    metadataOutput.metadataObjectTypes = [.qr, .ean13, .code128]
    

    If you would like to allow all available metadata object types you can use AVCaptureMetadataOutput property availableMetadataObjectTypeswhich return all available types:

    metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes
    

    If you would like to allow all of then except the faces which is the first one, you can drop the first element of the availableMetadataObjectTypes. Note that Apple might change the metadata elements order in the near future so it is better to manually select only the barcode types required by your app:

    metadataOutput.metadataObjectTypes =  Array(metadataOutput.availableMetadataObjectTypes.dropFirst())
    

    Just a few notes on your actual code. You shouldn't check the elements count if it is equal to zero to check if it is empty. Array has a property called isEmpty exactly for that if !metadataObjects.isEmpty { //.... Another option is if only the first element of the array is used I recommend using Array .first instead of subscript [0] which returns an optional element AVMetadataObject? and AVMetadataObject.ObjectType is redundant in your comparison:

    if let object = metadataObjects.first as? AVMetadataMachineReadableCodeObject {
        if object.type == .qr {
            if let text = object.stringValue {
                print(text)
                session.stopRunning()
                let alertVC = UIAlertController(title: "QR Code", message: text, preferredStyle: .alert)
                alertVC.addAction(UIAlertAction(title: "Ok", style: .default) { _ in
                    self.session.startRunning()
                })
                present(alertVC, animated: true)
            }
        }
        else
        if let text = object.stringValue {
            print("Other code detected: ", text)
        }
    }