Android Dexter Kotlin Request Runtime Permissions Example

listview section header kotlin, kotlin pick video from gallery or capture from camera, kotlin custom spinner with image, pull to refresh listview android, swipe to refresh recyclerview android, expandablelistview in kotlin, Kotlin Horizontal Progressbar Android, kotlin image slider from url, Kotlin GIF Animated Splash Screen, Kotlin RecyclerView Sectioned Header, kotlin indeterminate circular progressbar, android dexter kotlin, kotlin digital signature view, kotlin alertdialog with edittext, elasticsearch windows, android dexter kotlin

Let me introduce you to Android Dexter Kotlin Request Runtime Permissions Example.

Every android app need to ask for the runtime permissions to the user when they want sensitive data of the user’s android device.

In this example, you will learn to ask for runtime permissions in kotlin using dexter library.

In general, it is difficult to use android’s built in code and methods implement runtime permissions.

But dexter library makes this process simple and faster for us.

Using the classes and methods of the dexter library, we will be able to write runtime permissions code in no time.

First of all, go through the below video to show the final result of this tutorial.

Step 1. Gradle Working

In your android studio, make a fresh new project for making this android dexter kotlin project.

Now in this new project, open gradle file : build.gradle(Module:app)

You need to below line in this build.gradle(Module:app)

 implementation 'com.karumi:dexter:5.0.0'

Above file will fetch all the classes and methods of dexter library in our project.

So after this, we will be able to use this library and it’s source code directly into our project.

Step 2. Permissions in Manifest

Now open your AndroidManifest.xml file.

In this AndroidManifest.xml file, add the below lines

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />

You can see that above lines are defining various permissions like camera, read contact, call phone etc.

We will have to ask at runtime to the user for all the above permissions.

Step 3. Final Writings

Your project must have two files. One is activity_main.xml and another is MainActivity.kt

In your activity_main.xml file, add the below coding lines

<?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:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".MainActivity">

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:textSize="25sp"
            android:text="Single Permission"/>

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:id="@+id/btnCamera"
            android:text="Camera"/>

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:textSize="25sp"
            android:text="Multiple Permission"/>

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:id="@+id/btnMultiple"
            android:text="Contact, Storage, Audio"/>

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:id="@+id/btn"
            android:text="Snackbar Example"/>

</LinearLayout>

Above coding lines hold two text views and three buttons.

Text views are static so we will not change it’s text values in this project.

We will see what button click events are doing in the Kotlin file.

Now, open up your MainActivity.kt file and write down the below code snippet in it,

import android.Manifest
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.support.design.widget.Snackbar
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.DexterError
import com.karumi.dexter.listener.PermissionDeniedResponse
import com.karumi.dexter.listener.PermissionGrantedResponse
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.PermissionRequestErrorListener
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.karumi.dexter.listener.single.PermissionListener
import com.karumi.dexter.listener.single.SnackbarOnDeniedPermissionListener

class MainActivity : AppCompatActivity() {

    private var btnSingle: Button? = null
    private var btnMultiple: Button? = null
    private var btn: Button? = null
    private var snackbarPermissionListener: PermissionListener? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val parentLayout = findViewById<View>(android.R.id.content)

        snackbarPermissionListener = SnackbarOnDeniedPermissionListener.Builder
            .with(parentLayout, "Call Phone access is needed to call your dog")
            .withOpenSettingsButton("Settings")
            .withCallback(object : Snackbar.Callback() {
                override fun onShown(snackbar: Snackbar?) {
                    // Event handler for when the given Snackbar is visible
                }

                override fun onDismissed(snackbar: Snackbar?, event: Int) {
                    // Event handler for when the given Snackbar has been dismissed
                }
            }).build()

        btnSingle = findViewById(R.id.btnCamera)
        btnMultiple = findViewById(R.id.btnMultiple)
        btn = findViewById(R.id.btn)

        btn!!.setOnClickListener { requestSnackbarPermission() }

        btnSingle!!.setOnClickListener { requestSinglePermission() }

        btnMultiple!!.setOnClickListener { requestMultiplePermissions() }

    }

    private fun requestMultiplePermissions() {
        Dexter.withActivity(this)
            .withPermissions(
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .withListener(object : MultiplePermissionsListener {
                override fun onPermissionsChecked(report: MultiplePermissionsReport) {
                    // check if all permissions are granted
                    if (report.areAllPermissionsGranted()) {
                        Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT)
                            .show()
                    }

                    // check for permanent denial of any permission
                    if (report.isAnyPermissionPermanentlyDenied) {
                        // show alert dialog navigating to Settings
                        openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(
                    permissions: List<PermissionRequest>,
                    token: PermissionToken
                ) {
                    token.continuePermissionRequest()
                }
            }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() }
            .onSameThread()
            .check()
    }

    private fun requestSinglePermission() {

        Dexter.withActivity(this)
            .withPermission(Manifest.permission.CAMERA)
            .withListener(object : PermissionListener {
                override fun onPermissionGranted(response: PermissionGrantedResponse) {
                    //Single Permission is granted
                    Toast.makeText(this@MainActivity, "Single permission is granted!", Toast.LENGTH_SHORT).show()
                }

                override fun onPermissionDenied(response: PermissionDeniedResponse) {
                    // check for permanent denial of permission
                    if (response.isPermanentlyDenied) {
                        openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest, token: PermissionToken) {
                    token.continuePermissionRequest()
                }
            }).check()

    }

    private fun openSettingsDialog() {

        val builder = AlertDialog.Builder(this@MainActivity)
        builder.setTitle("Required Permissions")
        builder.setMessage("This app require permission to use awesome feature. Grant them in app settings.")
        builder.setPositiveButton("Take Me To SETTINGS") { dialog, which ->
            dialog.cancel()
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            val uri = Uri.fromParts("package", packageName, null)
            intent.data = uri
            startActivityForResult(intent, 101)
        }
        builder.setNegativeButton(
            "Cancel"
        ) { dialog, which -> dialog.cancel() }
        builder.show()

    }

    private fun requestSnackbarPermission() {

        Dexter.withActivity(this)
            .withPermission(Manifest.permission.CALL_PHONE)
            .withListener(snackbarPermissionListener)
            .check()

    }

}

More Reference For Above

First of all, read the below lines of code

  private var btnSingle: Button? = null
    private var btnMultiple: Button? = null
    private var btn: Button? = null
    private var snackbarPermissionListener: PermissionListener? = null

First three lines are giving us the objects of the button class.

Last line is making the object of the PermissionListener class.

Now attend the below coding structure

  btn!!.setOnClickListener { requestSnackbarPermission() }

When the user clicks the “SNACKBAR EXAMPLE”, Compiler will call requestSnackbarPermission() method.

Below are the coding lines for requestSnackbarPermission() method.

   private fun requestSnackbarPermission() {

        Dexter.withActivity(this)
            .withPermission(Manifest.permission.CALL_PHONE)
            .withListener(snackbarPermissionListener)
            .check()

    }

This method will ask for the CALL_PHONE permission to the user.

If user allow permission then compiler will not do anything but if user denies the permission then it will show a snackbar with settings button.

We are displaying a snackbar at the bottom of the screen.

Snackbar is similar to the toast which shows some short messages to the user to inform him about certain important facts.

When the user clicks the settings button of the snackbar, compiler will take hm to the settings of the app where he can turn on or off various permissions.

Now see the following code part

 btnSingle!!.setOnClickListener { requestSinglePermission() }

When the user clicks the btnSingle button, compiler will call requestSinglePermission() method,

Below is the code for requestSinglePermission() method

  private fun requestSinglePermission() {

        Dexter.withActivity(this)
            .withPermission(Manifest.permission.CAMERA)
            .withListener(object : PermissionListener {
                override fun onPermissionGranted(response: PermissionGrantedResponse) {
                    //Single Permission is granted
                    Toast.makeText(this@MainActivity, "Single permission is granted!", Toast.LENGTH_SHORT).show()
                }

                override fun onPermissionDenied(response: PermissionDeniedResponse) {
                    // check for permanent denial of permission
                    if (response.isPermanentlyDenied) {
                        openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest, token: PermissionToken) {
                    token.continuePermissionRequest()
                }
            }).check()

    }

As per the name suggests, this method ask for single runtime permission to the user.

Compiler will use the various classes and methods of Dexter library to ask for CAMERA permission in the above code.

Above method will handle all three possible scenarios ,

1. User allows the permission : Here, compiler will show the Toast saying “Single Permission is granted !”

2. User Denies the permission : Compiler will not do anything in this case.

3. User clicks the “Don’t ask again checkbox” and then Denies the permission : In this case, compiler will call  openSettingsDialog() method.

Below are the source line for openSettingsDialog() method,

 private fun openSettingsDialog() {

        val builder = AlertDialog.Builder(this@MainActivity)
        builder.setTitle("Required Permissions")
        builder.setMessage("This app require permission to use awesome feature. Grant them in app settings.")
        builder.setPositiveButton("Take Me To SETTINGS") { dialog, which ->
            dialog.cancel()
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            val uri = Uri.fromParts("package", packageName, null)
            intent.data = uri
            startActivityForResult(intent, 101)
        }
        builder.setNegativeButton(
            "Cancel"
        ) { dialog, which -> dialog.cancel() }
        builder.show()

    }

This dialog will have one message which informs user regarding the importance of the permission.

Other than the message, this dialog will also have two buttons : CANCEL and TAKE ME TO SETTINGS

On the click of CANCEL button, compiler will simply close the dialog.

Click event of other button will led the user to the settings of the app where he can manually turn on or off any permission.

Now read the following coding flow

 private fun requestMultiplePermissions() {
        Dexter.withActivity(this)
            .withPermissions(
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .withListener(object : MultiplePermissionsListener {
                override fun onPermissionsChecked(report: MultiplePermissionsReport) {
                    // check if all permissions are granted
                    if (report.areAllPermissionsGranted()) {
                        Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT)
                            .show()
                    }

                    // check for permanent denial of any permission
                    if (report.isAnyPermissionPermanentlyDenied) {
                        // show alert dialog navigating to Settings
                        openSettingsDialog()
                    }
                }

                override fun onPermissionRationaleShouldBeShown(
                    permissions: List<PermissionRequest>,
                    token: PermissionToken
                ) {
                    token.continuePermissionRequest()
                }
            }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() }
            .onSameThread()
            .check()
    }

Compiler will run the above code when the user clicks the “CONTACT,STORAGE,AUDIO” button.

Here, compiler will run requestMultiplePermissions() method.

This method is asking multiple permissions to the user. I have three permissions in this method, but you can add or delete permission as per your requirement.

If the user grants all the permissions then compiler will show a Toast like “All permissions are granted b user !!”

but the user makes permanent denial of any permission (user clicks on “Don’t ask again check and then denies permission”) then compiler will run openSettingsDialog() method.

More Tutorials

Android Runtime Permission with Dexter Example in JAVA

Multiple Runtime Permission without external Library

Source Code of Android Dexter Kotlin From Github

Click me to go to github and download full source code