47

QR Code Reader Android Kotlin Tutorial using ML Kit

 3 years ago
source link: https://www.simplifiedcoding.net/qr-code-reader-android-kotlin/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

QR Code Reader Android Kotlin Tutorial using ML Kit

QR Code has became very popular in India. Even small vendors accept digital payments, and we use any Payment App (Google Pay, PhonePe, PayTm) to scan a QR Code and pay them easily. And in your next android app project, you might want to add a QR Code Scanner. And that is why I am here with QR Code Reader Android Kotlin Tutorial.

In this tutorial we will use ML Kit to build a QR Code Scanner Application. If you want to know about what exactly we are going to build, then watch the video below.

You can actually put any kind of information in a QR Code; and for this example I’ve used URL.

What is QR Code?

As we already discussed, almost all digital app based payments in India uses QR Code; so I assume you’ve seen a QR Code already. It stands for Quick Response Code. QR Code is a type of Barcode; it is a two dimensional Bar Code. It contains black squares over a white background, and we can put some data in it that can be read by camera.

Below you can see a sample QR Code, and you can use this QR Code to test the application that you will build in this tutorial.

QR Code Reader Android KotlinQR Code Reader Android Kotlin

Building a QR Code Reader Android App

Now let’s build our application that can read information from a QR Code.

Pre-requisites

I will be using the following things, for this project.

  • ML-Kit Barcode Scanning – To scan the QR Code
  • Bottom Sheet – To display the information after reading from QR Code
  • CameraX – For creating camera that will read QR Code
  • Jsoup – To read URL Meta Data

Android Studio Project

Now let’s create our project. I have created a new project using an Empty Activity and the first step is adding required dependencies.

  • Open app level build.gradle file and add the following dependencies.
    //ML Kit Barcode Scanning
    implementation 'com.google.mlkit:barcode-scanning:16.0.3'
    //CameraX Dependencies
    implementation "androidx.camera:camera-core:1.0.0-beta10"
    implementation "androidx.camera:camera-camera2:1.0.0-beta10"
    implementation "androidx.camera:camera-lifecycle:1.0.0-beta10"
    implementation "androidx.camera:camera-view:1.0.0-alpha10"
    implementation "androidx.camera:camera-extensions:1.0.0-alpha10"
    implementation 'com.google.android.material:material:1.3.0-alpha02'
    //Library to get URL Meta Data
    implementation 'org.jsoup:jsoup:1.13.1'
  • We also need to add Java8 compileOptions; so add the following inside android block.
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
  • Now you can sync the project.

Designing App’s UI

Scanner

We need camera that will scan the QR Code and I will create it inside MainActivity .

I’ve created the following UI Design.

QR Code Reader Android Kotlin
QR Code Reader Android Kotlin

To create the design like this, you can use the following XML code.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000000">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:id="@+id/text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="140dp"
                android:text="QR Code Reader Android\nusing ML Kit"
                android:textAlignment="center"
                android:textColor="#FAFAFA"
                android:textSize="24sp" />
            <ImageView
                android:layout_width="300dp"
                android:layout_height="350dp"
                android:layout_below="@id/text_view"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="34dp"
                android:background="@drawable/background_rect" />
        </RelativeLayout>
    </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Everything is very simple and straightforward, you just need to see the <androidx.camera.view.PreviewView />  here, because I think this might be a new thing for you if you have not already used CameraX.

PreviewView  is for our Camera Preview.

Bottom Sheet

Once we have scanned the QR Code and got the information from it; we will show the information to a BottomSheet. And below is the design of my BottomSheet.

BottomSheet

For bottom sheet I’ve created a layout file named bottom_sheet_barcode_data.xml .

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:orientation="vertical"
    android:padding="16dp">
    <TextView
        android:id="@+id/text_view_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="8dp"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Title"
        android:textColor="#2B2B2B"
        tools:text="Simplified Coding - QR Code Reader" />
    <TextView
        android:id="@+id/text_view_desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="8dp"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"
        android:textColor="#6C6C6C"
        android:textSize="10sp"
        tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus sed fermentum odio. Donec laoreet nisi nisl. Praesent at mauris enim. Suspendisse metus quam, congue eu nunc a, lacinia placerat orci" />
    <TextView
        android:id="@+id/text_view_link"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Small"
        android:textColor="#002865"
        tools:text="https://www.youtube.com/SimplifiedCoding?sub_confirmation=1" />
    <TextView
        android:id="@+id/text_view_visit_link"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="12dp"
        android:background="#00A5E6"
        android:paddingLeft="12dp"
        android:paddingTop="4dp"
        android:paddingRight="12dp"
        android:paddingBottom="4dp"
        android:text="Visit Link"
        android:textColor="#ffffff" />
</LinearLayout>

We have all the required designs ready now.

Building Camera

The first thing that we need in this app is the Camera. Because camera will read the QR Code. So let’s build the camera.

Camera Permission

  • Add Camera Permission in AndroidManifest.xml.
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />

I’ve also added the internet permission, because we need it to fetch URL content.

  • To make things smaller, I am not asking Camera Permission in the code, but I will directly open the settings page, if the Camera Permission is not given.
    private fun checkCameraPermission() {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
            Intent().also {
                it.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                it.data = Uri.fromParts("package", packageName, null)
                startActivity(it)
                finish()
  • It is not a good practice to do, so I would like you all to add the run time permission code in your project.
  • We will call the above checkCameraPermission()  function inside the onCreate()  of MainActivity .

Camera

Now let’s finally build our camera.

  • First we need to define these objects.
    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
    private lateinit var cameraExecutor: ExecutorService
  • Then we will initialize these inside onCreate()  function.
    cameraExecutor = Executors.newSingleThreadExecutor()
    cameraProviderFuture = ProcessCameraProvider.getInstance(this)
  • Now we can get the cameraProvider, from cameraProviderFuture and then we can bind the camera preview to our PreviewView.
    cameraProviderFuture.addListener(Runnable {
        val cameraProvider = cameraProviderFuture.get()
        bindPreview(cameraProvider)
    }, ContextCompat.getMainExecutor(this))
  • Here is the bindPreview()  function
    @SuppressLint("UnsafeExperimentalUsageError")
    private fun bindPreview(cameraProvider: ProcessCameraProvider) {
        val preview: Preview = Preview.Builder()
            .build()
        val cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()
        preview.setSurfaceProvider(previewView.createSurfaceProvider(null))
        cameraProvider.bindToLifecycle(
            this as LifecycleOwner,
            cameraSelector,
            preview

Now you can run your application and you will see the camera preview. 

Scanning QR Code

We have the camera and now it is the time to check if our camera is pointed to a QR Code or not. Basically we want to read if there is a QR Code to read.

  • To achieve this thing, we need to create an ImageAnalysis.Analyzer .
class MyImageAnalyzer: ImageAnalysis.Analyzer {
    override fun analyze(imageProxy: ImageProxy) {
        scanBarcode(imageProxy)
    @SuppressLint("UnsafeExperimentalUsageError")
    private fun scanBarcode(imageProxy: ImageProxy) {
        imageProxy.image?.let { image ->
            val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
            val scanner = BarcodeScanning.getClient()
            scanner.process(inputImage)
                .addOnCompleteListener {
                    imageProxy.close()
                    if (it.isSuccessful) {
                        readBarcodeData(it.result as List<Barcode>)
                    } else {
                        it.exception?.printStackTrace()
    private fun readBarcodeData(barcodes: List<Barcode>) {
        for (barcode in barcodes) {
            when (barcode.valueType) {
                //you can check if the barcode has other values
                //For now I am using it just for URL
                Barcode.TYPE_URL -> {
                    //we have the URL here
                    val url = barcode.url?.url
  • Now, we have the URL that we read from the QR Code. We just need to show it. You can display it anywhere you want. I have used BottomSheet for it.
  • But before going to BottomSheet, we need to add this Analyzer to our Camera. We will do it inside bindPreview()  function.
        val imageAnalysis = ImageAnalysis.Builder()
            .setTargetResolution(Size(1280, 720))
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()
        imageAnalysis.setAnalyzer(cameraExecutor, analyzer)
        cameraProvider.bindToLifecycle(
            this as LifecycleOwner,
            cameraSelector,
            imageAnalysis,
            preview
  • First we have create an ImageAnalysis , using ImageAnalysis.Builder()  and then we set the analyzer  to it.
  • analyzer  is the instance of MyImageAnalyzer  that we just created.
  • Finally we passed the imageAnalysis  as the third parameter to bindToLifecycle()  function.

Displaying QR Code in BottomSheet

  • The bottom sheet design we have already created. And here is the class to display the URL in the bottom sheet.
class BarcodeResultBottomSheet : BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.bottom_sheet_barcode_data, container, false)
    //We will call this function to update the URL displayed
    fun updateURL(url: String) {
        fetchUrlMetaData(url) { title, desc ->
            view?.apply {
                findViewById<TextView>(R.id.text_view_title)?.text = title
                findViewById<TextView>(R.id.text_view_desc)?.text = desc
                findViewById<TextView>(R.id.text_view_link)?.text = url
                findViewById<TextView>(R.id.text_view_visit_link).setOnClickListener { _ ->
                    Intent(Intent.ACTION_VIEW).also {
                        it.data = Uri.parse(url)
                        startActivity(it)
    //this function will fetch URL data
    private fun fetchUrlMetaData(
        url: String,
        callback: (title: String, desc: String) -> Unit
        val executor = Executors.newSingleThreadExecutor()
        val handler = Handler(Looper.getMainLooper())
        executor.execute {
            val doc = Jsoup.connect(url).get()
            val desc = doc.select("meta[name=description]")[0].attr("content")
            handler.post {
                callback(doc.title(), desc)
  • Now we just need to use this BottomSheet in our Image Analyzer class.
class MyImageAnalyzer(
    private val fragmentManager: FragmentManager
) : ImageAnalysis.Analyzer {
    private var bottomSheet = BarcodeResultBottomSheet()
    override fun analyze(imageProxy: ImageProxy) {
        scanBarcode(imageProxy)
    @SuppressLint("UnsafeExperimentalUsageError")
    private fun scanBarcode(imageProxy: ImageProxy) {
        imageProxy.image?.let { image ->
            val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
            val scanner = BarcodeScanning.getClient()
            scanner.process(inputImage)
                .addOnCompleteListener {
                    imageProxy.close()
                    if (it.isSuccessful) {
                        readBarcodeData(it.result as List<Barcode>)
                    } else {
                        it.exception?.printStackTrace()
    private fun readBarcodeData(barcodes: List<Barcode>) {
        for (barcode in barcodes) {
            when (barcode.valueType) {
                Barcode.TYPE_URL -> {
                    if (!bottomSheet.isAdded)
                        bottomSheet.show(fragmentManager, "")
                    bottomSheet.updateURL(barcode.url?.url.toString())
  • You just need to pass fragmentManager  while creating analyzer in MainActivity .

And that’s it, you have successfully built your QR Code Reader Android Application using ML Kit.

QR Code Reader Android Kotlin Source Code

In case you are still confused or having some problem while building your QR Code Reader Android App, then here is my source code that is perfectly working.

So that is all for this QR Code Reader tutorial friends. I hope you enjoyed the tutorial and built your own QR Code Reader App. Feel free to leave your comments below if you have any query or question. Thank You ♥️

Hi, my name is Belal Khan and I am a Google Developers Expert (GDE) for Android. The passion of teaching made me create this blog. If you are an Android Developer, or you are learning about Android Development, then I can help you a lot with Simplified Coding.

Checkout these tutorials as well:

  • Laravel REST API Authentication using Passport
  • Android Push Notification Tutorial using FCM HTTP V1
  • Kotlin Coroutines Tutorial for Android - Start using Coroutines in Your App
  • Android MVVM Tutorial - Build an App using MVVM Design Pattern
  • Android Navigation Tutorial for Fragments using Bottom Navigation
  • Firebase Phone Authentication Android Tutorial

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK