How to read a Barcode or QRCode with Swift — Programming with Swift
Checkout my other posts over at programmingwithswift.com
I was looking online at how to read a Barcode or QRCode using the device camera. All the tutorials I found were putting all the code into the view controller which I was not a fan of.
In this tutorial I will show you how to read a Barcode or QRCode using the device camera with Swift and keeping that logic in a separate class that is easy to use.
Step 1: Create the Scanner class
This step is simple all you need to do is create a new class called Scanner that inherits from NSObject and import AVFoundation.
Step 2: Add the properties to the Scanner class
Step 2 is just as simple as step 1, we just need to add all the properties that we will need later on.
Your Scanner class should now look like this:
Step 3: Creating the AVCaptureSession
To start off, what is an AVCaptureSession? According to apple it is: ”An object that manages capture activity and coordinates the flow of data from input devices to capture outputs.”
So basically you will get a device input, in this case it will be the device camera and then you create an output for it which we will see later.
In your Scanner class add a private function called createCaptureSession and this will return an AVCaptureSession. Your function should look like this:
Next we will create a new variable called captureSession, this will be a new instance of AVCaptureSession.
After that we will create another variable called captureDevice which will be the device that we add as an input to the captureSession later.
This is how the code will look:
Step 5: Create and add the inputs and outputs
Firstly we need to create a do catch. This is because when creating an AVCaptureDeviceInput it could throw and exception.
Now we can start adding our input and output to the captureSession. To do this we will create two new variables. The first one will be called deviceInput and the second one will be metaDataOutput.
The device input will use the captureDevice that we created earlier in order to create a new AVCaptureDeviceInput. The metaDataOutput will be a new instance of AVCatpureMetadataOutput. Your code needs to look like this:
Now that we have created those variables we can start adding them to the captureSession as an input and output.
So in order to add an input or output we first need to check if it can be added to the captureSession or not. If it cannot then we will just return nil as we need to be able to have both added.
We will add the input first and then do the output. The output has a little bit more code which is what will allow us to get the data from the Barcodes and QRCode that we will scan.
To add the deviceInput to the captureSession add the following in the do just under the previous two variables like this:
Now we can do the same with the output. You will see that there is more code in the output. The start is basically the same, but then we need to cast the view controller that we added at the start of the class to AVCaptureMetadataOutputObjectsDelegate. We need to do that so that we can use it as a delegate. The delegate method that we will implement later on will have all the info from the Barcodes or QRCodes that we scan.
After we cast the view controller we set it as the delegate for the metaDataOutput variable we made earlier in this function. Once we have added that we will tell it what types of codes it can scan. We will implement that method next, as you can see the method that returns the type of codes that we can scan is called metaObjectTypes.
To add the output and set the delegate, your code should look like the below. Note at the moment you will get an error since we have not yet implemented the metaObjectTypes function.
Then right at the end of the function we will just return the captureSession. At the end your function should look like this:
Step 6: Create the metaObjectTypes function
In the previous step we called function that we have not yet created, so lets quickly create that function. All this function will do is return an array of all the Barcodes and QRCode that we will be able to scan.
Step 7: Create the preview layer
The preview layer is exactly what it says. It is a layer that will show us a preview, in other words it will show us the video stream from the camera.
This is a very easy thing to setup. All that we need is a view and a captureSession to be passed through as arguments, and then we will be able to return an AVCaptureVideoPreviewLayer. To create a new AVCaptureVideoPreviewLayer we will use the captureSession that we pass through. The view will be used to set the frame of the preview layer.
The code looks like this:
Step 8: Create the init function for the Scanner
It me seem back to front with me only talking about the init function now but I done that so that we already know what is everything is used for in the code.
What you will need to do is to create a new init function just under the private properties that we created earlier.
The init function will take three arguments. It will take a view controller, a view and a handler method.
The view controller that we pass through will need to conform to the AVCaptureMetadataOutputObjectsDelegate delegate. We spoke about this delegate before when we cast the view controller to this type. This delegate allows us to get the metadata from the video stream which we will use to get the data from the Barcodes or QRCodes that we scan.
The view will be used to set the frame of the preview layer which we done in step 7.
The codeOutputHandler will be function that we pass the value of the Barcode or QRCode to.
To start off with, your init function should look like this:
Next in your init function, straight after the super.init(), we will create and set the captureSession. We will also add the preview layer as a sub layer to the view that we passed through to the init function.
This code will look like this:
The final init function should look like this:
Step 9: Create start and stop functions to start or stop the capture session
This is quite straightforward. All we are going to do is call a function called startRunning or stopRunning on the captureSession that we created in the init function in the previous step.
In these functions we check to make sure that a captureSession is not nil, if it is then we will stop the function by returning. After that we will check whether the capture session is running or not and then call either the startRunning or stopRunning as mentioned before.
Keep in mind these functions are not private since we might need to start or stop the capture session outside of the Scanner class.
The code looks like this:
Step 10: Initialise the Scanner and implement delegate method
In this step we are going to initialise the Scanner as well as implement the delegate method in the view controller. We will also be creating the function that we pass through as the argument for the codeOutputHandler.
Firstly, lets create the handler function as it is the easiest to start with. This function takes one argument which is the code(Barcode or QRCode) that we find in the metadata. In this example I will just print the code to the console, but you can do whatever you need to do with it from this function.
Next we will create the new instance of the Scanner. In this example I am going to initialise the Scanner in a view controller. Create a new property called, scanner. This will of type Scanner and it will be optional. It will look like this: var scanner: Scanner?
When I create the new instance of Scanner, I will use the view controller that I am in for the withViewController argument, the view argument will just be the view that every view controller has and then for the codeOutputHandler argument I will pass through the handleCode function we created above.
After we have initialised it we will start the camera session. The code looks like this:
Now we need to implement the delegate method. Before I carry on I need to show you what my view controller looks like. Note that in order to use this delegate you will need to import AVFoundation in the view controller file.
As you can see it inherits from UIViewController but it also conforms to AVCaptureMetadataOuputObjectsDelegate.
To implement this you will need to create the function that is in the delegate. The function is as follows:
Now, the whole point of this article is that we keep as much as possible in the Scanner class that we have created. Therefore it doesn’t make sense that we handle the Barcode and QRCode information directly in this delegate function.
So what we need to do is add a new function to our Scanner class that takes the same arguments as this delegate function takes.
In the Scanner class create a new function that looks like this:
Now we go back to the delegate function and we will call this new function from it. Your delegate function needs to be updated to look like this:
Step 11: Implement the scannerDelegate function in Scanner
All we need to do now is implement the scannerDelegate function and you should be able to run and scan Barcodes and QRCodes.
In the scannerDelegate function we will stop the captureSession. This prevents us from calling the codeOutputHandler multiple times and it will only be called once. When we call the this the camera will freeze which is what stopping the session will do. You will need to handle this however you need to in your app, if that means navigating to a new view, or hiding this view it is up to you.
Add this code to stop the session:
After we have stopped the captureSession we need to get the readable object from the metadataObjects argument and get the string value of that readable object.
To do that add this code underneath where you self.requestCaptureSessionStopRunning(). The code that you need to add looks like this:
Once we have the string value we pass it through as an argument to the codeOutputHandler function like this:
Your scannerDelegate function should look like this now:
That is it! You should now be able to run the project and scan Barcodes and QRCodes!
You can find the full source here.
Other articles:
How to use SKStoreReviewController tutorial: https://medium.com/programming-with-swift/skstorereviewcontroller-tutorial-programming-with-swift-31a4faded01f
How to create a custom UITableViewCell with: Swift:https://medium.com/programming-with-swift/create-a-custom-uitableviewcell-with-swift-6d7eb7389f19