Zxing Android library is a great Android QR Scanner code library that you can use to build an Android QR code scanning app. In this tutorial, we will teach you how to do the same in Java and Kotlin Programming language.
Need some career advice or prepping for an Android developer interview? Hit me up on Topmate.io, and let's chat!
What is a QR Code?
A QR Code is 2 dimensional Bar code which was initially designed in 1994 for the automobile industry in Japan. It’s an optical coded label that can be decrypted and read by machines.
Generating your own QR Code
You can start this example by creating your own QR Code. Visit this website here and insert a sample text or url.
The QR Code will automatically get generated that you can scan later after building the app.
Zxing Android Library
To build an android app for scanning QR Codes we will be using Android Library which is based on Zxing QR code scanning android library.
We will also need to declare the CAMERA permission in Android manifest to access the device camera.
Once the user opens the app, the app will request the permission, if not granted and then scan the QR Code automatically and the decoded result text will appear as a Toast message.
You can alternatively, use the text message and make it appear in a SnackBar or TextView.
The source code files are available in the end for download .
Creating QR Code Scanner App
Creating Android Project
Open Android Studio and create a new project in Java or Kotlin (your preference, we have provided source code for both).
The Code Scanner Library supports both programming languages.
Implementing the dependency
Implement the following Code Scanner Dependency in build.gradle app level.
implementation 'com.budiyev.android:code-scanner:2.1.0'
Creating the Layout XML File
In the activity_main.xml or where ever you want to create the code scanner, add the following line of XML code.
<com.budiyev.android.codescanner.CodeScannerView
android:id="@+id/scanner_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:autoFocusButtonColor="@android:color/white"
app:autoFocusButtonVisible="true"
app:flashButtonColor="@android:color/white"
app:flashButtonVisible="true"
app:frameColor="@android:color/white"
app:frameCornersSize="50dp"
app:frameCornersRadius="0dp"
app:frameAspectRatioWidth="1"
app:frameAspectRatioHeight="1"
app:frameSize="0.75"
app:frameThickness="2dp"
app:maskColor="#77000000"/>
In the code above, we have created the CodeScannerView widget. In the widget, we have set following attributes:
- Focus button color
- Flash Button Color
- Frame to highlight the QR code boundary
- Frame border
- Mask
Declaring the required Permission
Declare the access to device Camera in AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/>
Building the QR Scanner (Java)
Requesting and Checking if permission Granted
Using ContextCompact, we will first check if the user has been granted the app, the required permission to access the device camera. If not then we will the user a prompt message.
// the code below appears in onCreate() method
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_DENIED){
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.CAMERA}, 123);
} else {
startScanning();
}
Once the permission is granted, we have to call startScanning() method again.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 123) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Camera permission granted", Toast.LENGTH_LONG).show();
startScanning();
} else {
Toast.makeText(this, "Camera permission denied", Toast.LENGTH_LONG).show();
}
}
}
Coding the Code Scanner
In the startScanning() method we will create the CodeScanner (private Variable) and CodeScannerView.
private CodeScanner mCodeScanner;
private void startScanning() {
CodeScannerView scannerView = findViewById(R.id.scanner_view);
mCodeScanner = new CodeScanner(this, scannerView);
mCodeScanner.setDecodeCallback(new DecodeCallback() {
@Override
public void onDecoded(@NonNull final Result result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result.getText(), Toast.LENGTH_SHORT).show();
}
});
}
});
scannerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mCodeScanner.startPreview();
}
});
}
The CodeScanner has a setDecodeCallback method that will get the result. It gets activated when scannerView is clicked, so we have a setOnClickListener method for the same.
As we are using the device camera, so in order to save battery and device resources, we will also override the onPause and onResume method to manage the code scanner.
@Override
protected void onResume() {
super.onResume();
if(mCodeScanner != null) {
mCodeScanner.startPreview();
}
}
@Override
protected void onPause() {
if(mCodeScanner != null) {
mCodeScanner.releaseResources();
}
super.onPause();
}
We’ve finally built the Code Scanner in Java using the zxing android library, You can build and run your app now.
The complete code for Java is here.
package com.androiddvlpr.zxingandroid;
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.budiyev.android.codescanner.CodeScanner;
import com.budiyev.android.codescanner.CodeScannerView;
import com.budiyev.android.codescanner.DecodeCallback;
import com.google.zxing.Result;
public class MainActivity extends AppCompatActivity {
private CodeScanner mCodeScanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_DENIED){
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.CAMERA}, 123);
} else {
startScanning();
}
}
private void startScanning() {
CodeScannerView scannerView = findViewById(R.id.scanner_view);
mCodeScanner = new CodeScanner(this, scannerView);
mCodeScanner.setDecodeCallback(new DecodeCallback() {
@Override
public void onDecoded(@NonNull final Result result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result.getText(), Toast.LENGTH_SHORT).show();
}
});
}
});
scannerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mCodeScanner.startPreview();
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 123) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Camera permission granted", Toast.LENGTH_LONG).show();
startScanning();
} else {
Toast.makeText(this, "Camera permission denied", Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onResume() {
super.onResume();
if(mCodeScanner != null) {
mCodeScanner.startPreview();
}
}
@Override
protected void onPause() {
if(mCodeScanner != null) {
mCodeScanner.releaseResources();
}
super.onPause();
}
}
Also see: Android Best Practices from Experienced Developers | Top 18 Curated List
Building the QR Scanner (Kotlin)
Requesting and Checking if permission Granted
Using ContextCompact, we will first check if the user has been granted the app, the required permission to access the device camera. If not then we will the user a prompt message.
Insert the following lines of code in the onCreate() method:
if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.CAMERA), 123)
} else {
startScanning()
}
Also we will listen for user response if the permission was not granted earlier and prompt appears. The code for the same is as follows:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 123) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Camera permission granted", Toast.LENGTH_LONG).show()
startScanning()
} else {
Toast.makeText(this, "Camera permission denied", Toast.LENGTH_LONG).show()
}
}
}
Coding the code scanner
In the startScanning() method we will create the CodeScanner (private Variable) and CodeScannerView.
private lateinit var codeScanner: CodeScanner
private fun startScanning() {
// Parameters (default values)
val scannerView: CodeScannerView = findViewById(R.id.scanner_view)
codeScanner = CodeScanner(this, scannerView)
codeScanner.camera = CodeScanner.CAMERA_BACK // or CAMERA_FRONT or specific camera id
codeScanner.formats = CodeScanner.ALL_FORMATS // list of type BarcodeFormat,
// ex. listOf(BarcodeFormat.QR_CODE)
codeScanner.autoFocusMode = AutoFocusMode.SAFE // or CONTINUOUS
codeScanner.scanMode = ScanMode.SINGLE // or CONTINUOUS or PREVIEW
codeScanner.isAutoFocusEnabled = true // Whether to enable auto focus or not
codeScanner.isFlashEnabled = false // Whether to enable flash or not
// Callbacks
codeScanner.decodeCallback = DecodeCallback {
runOnUiThread {
Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()
}
}
codeScanner.errorCallback = ErrorCallback { // or ErrorCallback.SUPPRESS
runOnUiThread {
Toast.makeText(this, "Camera initialization error: ${it.message}",
Toast.LENGTH_LONG).show()
}
}
scannerView.setOnClickListener {
codeScanner.startPreview()
}
}
In Kotlin you can see we have set various attributes for our code scanner will are as follows:
codeScanner.camera = CodeScanner.CAMERA_BACK // or CAMERA_FRONT or specific camera id
codeScanner.formats = CodeScanner.ALL_FORMATS // list of type BarcodeFormat,
// ex. listOf(BarcodeFormat.QR_CODE)
codeScanner.autoFocusMode = AutoFocusMode.SAFE // or CONTINUOUS
codeScanner.scanMode = ScanMode.SINGLE // or CONTINUOUS or PREVIEW
codeScanner.isAutoFocusEnabled = true // Whether to enable auto focus or not
codeScanner.isFlashEnabled = false // Whether to enable flash or not
Also there are two other callbacks for decoding and error handling.
In order to save the device battery and resources, We also need to override the onResume and the onPause method.
override fun onResume() {
super.onResume()
if(::codeScanner.isInitialized) {
codeScanner?.startPreview()
}
}
override fun onPause() {
if(::codeScanner.isInitialized) {
codeScanner?.releaseResources()
}
super.onPause()
}
TaDa! we have successfully built the QR Code scanner app using zxing android library.
The complete code for Kotlin is here:
package com.androiddvlpr.zxingandroidkotlin
import android.Manifest
import android.content.pm.PackageManager
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.widget.Toast
import com.budiyev.android.codescanner.*
class MainActivity : AppCompatActivity() {
private lateinit var codeScanner: CodeScanner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.CAMERA), 123)
} else {
startScanning()
}
}
private fun startScanning() {
// Parameters (default values)
val scannerView: CodeScannerView = findViewById(R.id.scanner_view)
codeScanner = CodeScanner(this, scannerView)
codeScanner.camera = CodeScanner.CAMERA_BACK // or CAMERA_FRONT or specific camera id
codeScanner.formats = CodeScanner.ALL_FORMATS // list of type BarcodeFormat,
// ex. listOf(BarcodeFormat.QR_CODE)
codeScanner.autoFocusMode = AutoFocusMode.SAFE // or CONTINUOUS
codeScanner.scanMode = ScanMode.SINGLE // or CONTINUOUS or PREVIEW
codeScanner.isAutoFocusEnabled = true // Whether to enable auto focus or not
codeScanner.isFlashEnabled = false // Whether to enable flash or not
// Callbacks
codeScanner.decodeCallback = DecodeCallback {
runOnUiThread {
Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()
}
}
codeScanner.errorCallback = ErrorCallback { // or ErrorCallback.SUPPRESS
runOnUiThread {
Toast.makeText(this, "Camera initialization error: ${it.message}",
Toast.LENGTH_LONG).show()
}
}
scannerView.setOnClickListener {
codeScanner.startPreview()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 123) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Camera permission granted", Toast.LENGTH_LONG).show()
startScanning()
} else {
Toast.makeText(this, "Camera permission denied", Toast.LENGTH_LONG).show()
}
}
}
override fun onResume() {
super.onResume()
if(::codeScanner.isInitialized) {
codeScanner?.startPreview()
}
}
override fun onPause() {
if(::codeScanner.isInitialized) {
codeScanner?.releaseResources()
}
super.onPause()
}
}