Barcode Recognition with Swift 3

I’m in the process of making a grocery list app that’s synced across my family’s devices, and thought of adding a cool feature to scan barcodes of popular groceries. Barcodes are recognized through two steps: finding the UPC number of the barcode, and then looking that number up on a database. The barcode doesn’t actually hold any information about the product, like a QR code, but rather only encodes the product number in an image. This number is product specific, so a product will have only one number universally. The problem with barcode recognition is the product lookup – barcode databases are INSANELY expensive, although they are well-curated and contain most products. They aren’t meant for individual developers, but rather for big corporations. Because of this, we’re going to be using the free SearchUPC.com database. The UPC of a product, or Universal Product Code, is the number that is recognized by the barcode scanner.

Using hyperoslo’s great BarcodeScanner, we can find the number, then query the SearchUPC database. I know there are some other free databases out there, but I found this one to have the most products. It’s ultimately up to personal preference, because free UPC databases are open source, and not curated. Most follow the same lookup feature though, so it’s just a matter of formatting the returned JSON differently. Also, the SearchUPC database produces minimal results, so if you want detailed information, use another database. I’m using it just to retrieve the product image and title, so I don’t need things like where to find the product, or price caps and stuff like that.

To get started, create a Podfile and add pod 'BarcodeScanner'. We’re also going to be using the SwiftyJSON and Alamofire pods. If you aren’t familiar with CocoaPod installation, read my CocoaPod installation guide. It will also walk you through adding and installing pods. Close the Podfile, and install the pods.

After importing the three frameworks at the top of your swift file, we’re going to start with the scanning of the barcode. First, we need to add 3 delegates to our View Controller. Next to where it says UIViewController, add BarcodeScannerCodeDelegate, BarcodeScannerErrorDelegate, BarcodeScannerDismissalDelegate. Find where you want to present your barcode scanner, and put

let controller = BarcodeScannerController()
controller.codeDelegate = self
controller.errorDelegate = self
controller.dismissalDelegate = self
present(controller, animated: true, completion: nil)

This establishes a BarcodeScanner View Controller, sets the delegates for printing the code, errors, and dismissal, and then presents the controller. Then, we’re going to add the necessary functions to handle scanning events. Add these to your ViewController file.

func barcodeScanner(_ controller: BarcodeScannerController, didCaptureCode code: String, type: String) {
    print(code)
}
func barcodeScanner(_ controller: BarcodeScannerController, didReceiveError error: Error) {
    print(error)
}
func barcodeScannerDidDismiss(_ controller: BarcodeScannerController) {
    controller.dismiss(animated: true, completion: nil)
}

This will enable us to print the code when the Barcode Scanner detects it, display or print errors that we can define, and dismiss the actual scanner.

We’re done with the scanning! Now onto the slightly harder stuff; the JSON retrieval. We’ll be using Alamofire for the API call, and SwiftyJSON to parse the JSON easily. Before any of that, you’ll need to make an API key. To do that, sign up at SearchUPC.com. This will give you links to call in order to retrieve product data. Go back into your code, and insert this into your didCaptureCode method:


if noResult {
    noResult = false
    Alamofire.request("your link").responseJSON { response in
        if let result = response.result.value {
            let json = JSON(result)
            if let newProd = json["0"]["productname"].string {
                //This prints the product name
                print(newProd as! String)
                //This prints the product image URL
                print(json["0"]["imageurl"].string!)
            }
            controller.dismiss(animated: true, completion: nil)
        }
    }
    controller.reset()
}

I know some of this code might be cryptic, so let’s walk through it. The variable, noResult, is there so that this block of code is only executed once. For some reason, the BarcodeScanner framework sometimes runs the didCaptureCode more than once after detecting a barcode, so this ensures we only make one API call. After verifying that we don’t have a result yet, we set noResult to false, meaning that we actually do have a result. Then, we send the GET request. Replace where it says, “your link“, to the url that says SECURE URL (HTTPS), under Method: GetProductJSON. This will include your access token. Finally, replace upc_code with \(code as! String), making sure that the whole url is wrapped in quotes. The next line makes sure that there is a result, and if so, makes a variable called result with the JSON. We’ll use SwiftyJSON to parse the JSON into a type of array, where we can get values by keys or indexes easily. That’s stored in the json variable. Just to make sure there is an entry for a product, we check if there is a value for the key, "productname". If there is, we print out the product name, and the url of its image. I won’t be going into downloading an image from a URL, but a simple Google search should give you the answer. After we’ve gotten our results, we dismiss the Barcode Scanner Controller and reset it.

That’s it! You’ve successfully scanned and recognized a barcode. If it doesn’t work sometimes, there isn’t any error with the code – it just means that the database doesn’t have an entry for that particular product. Also, if you don’t get a result for a product, try twice just to make sure. Sometimes I find that I have to try twice sometimes to get product info.

/ Free Portfolio Plugin for WordPress by Silicon Themes.