We all know that Android Marshmallow introduced runtime permissions letting user to allow or deny any permission at runtime. Implementing runtime permissions is a tedious process and developer needs to write lot of code just to get a single permission.

In this article, we are going to simplify the process of adding the runtime permissions using Dexter library. Using this library, the permissions can be implemented in few minutes.

android-runtime-permissions-using-dexter

This is an introductory article about the Dexter covering basic features offered by the library. Dexter provides other features like using it with SnackBar, different types of listeners, error handling and few other. You can find more information on Dexter’s developer page.

1. Dexter Permissions Library

To get started with Dexter, add the dependency in your build.gradle

dependencies {
    // Dexter runtime permissions
    implementation 'com.karumi:dexter:4.2.0'
}

1.1 Requesting Single Permission

To request a single permission, you can use withPermission() method by passing the required permission. You also need a PermissionListener callback to receive the state of the permission.

> onPermissionGranted() will be called once the permission is granted.

> onPermissionDenied() will be called when the permission is denied. Here you can check whether the permission is permanently denied by using response.isPermanentlyDenied() condition.

The below code requests CAMERA permission.

Dexter.withActivity(this)
                .withPermission(Manifest.permission.CAMERA)
                .withListener(new PermissionListener() {
                    @Override
                    public void onPermissionGranted(PermissionGrantedResponse response) {
                        // permission is granted, open the camera
                    }

                    @Override
                    public void onPermissionDenied(PermissionDeniedResponse response) {
                        // check for permanent denial of permission
                        if (response.isPermanentlyDenied()) {
                            // navigate user to app settings
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();

1.2 Requesting Multiple Permissions

To request multiple permissions at the same time, you can use withPermissions() method. Below code requests STORAGE and LOCATION permissions.

Dexter.withActivity(this)
                .withPermissions(
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        // check if all permissions are granted
                        if (report.areAllPermissionsGranted()) {
                            // do you work now
                        }

                        // check for permanent denial of any permission
                        if (report.isAnyPermissionPermanentlyDenied()) {
                            // permission is denied permenantly, navigate user to app settings
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                })
                .onSameThread()
                .check();

1.3 Error Handling

You can also catch any errors occurred while integrating the library using PermissionRequestErrorListener.

Dexter.withActivity(this)
                .withPermissions(
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                .withListener(listener)
                .withErrorListener(new PermissionRequestErrorListener() {
                    @Override
                    public void onError(DexterError error) {
                        Toast.makeText(getApplicationContext(), "Error occurred! " + error.toString(), Toast.LENGTH_SHORT).show();
                    }
                })
                .check();

Now let’s see how to use Dexter in an example project.

2. Creating New Project

1. Create a new project in Android Studio from File β‡’ New Project and select Basic Activity from templates.

2. Add Dexter dependency to your build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    // ...

    // Dexter runtime permissions
    implementation 'com.karumi:dexter:4.2.0'
}

3. Open the layout file of your main activity (activity_main.xml and content_main.xml) and add two buttons to test different permission methods.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="info.androidhive.dexterpermissions.MainActivity"
    tools:showIn="@layout/activity_main">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:orientation="vertical"
        android:layout_centerHorizontal="true"
        android:paddingLeft="16dp"
        android:paddingRight="16dp">

        <Button
            android:id="@+id/btn_camera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:text="CAMERA PERMISSION" />

        <Button
            android:id="@+id/btn_storage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="MULTIPLE PERMISSIONS" />

    </LinearLayout>
</RelativeLayout>

4. Open MainActivity.java and do the modification as shown below.

> requestStoragePermission() requests for camera permission.

> requestStoragePermission() requests multiple permissions at once.

> response.isPermanentlyDenied() and report.isAnyPermissionPermanentlyDenied() checks if the permission is denied permanently. Here we have to navigate user to app settings screen by showing a dialog.

package info.androidhive.dexterpermissions;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
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 java.util.List;

public class MainActivity extends AppCompatActivity {

    private Button btnCamera, btnStorage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        btnCamera = findViewById(R.id.btn_camera);
        btnStorage = findViewById(R.id.btn_storage);

        btnCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestCameraPermission();
            }
        });

        btnStorage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestStoragePermission();
            }
        });
    }

    /**
     * Requesting multiple permissions (storage and location) at once
     * This uses multiple permission model from dexter
     * On permanent denial opens settings dialog
     */
    private void requestStoragePermission() {
        Dexter.withActivity(this)
                .withPermissions(
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        // check if all permissions are granted
                        if (report.areAllPermissionsGranted()) {
                            Toast.makeText(getApplicationContext(), "All permissions are granted!", Toast.LENGTH_SHORT).show();
                        }

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

                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).
                withErrorListener(new PermissionRequestErrorListener() {
                    @Override
                    public void onError(DexterError error) {
                        Toast.makeText(getApplicationContext(), "Error occurred! ", Toast.LENGTH_SHORT).show();
                    }
                })
                .onSameThread()
                .check();
    }

    /**
     * Requesting camera permission
     * This uses single permission model from dexter
     * Once the permission granted, opens the camera
     * On permanent denial opens settings dialog
     */
    private void requestCameraPermission() {
        Dexter.withActivity(this)
                .withPermission(Manifest.permission.CAMERA)
                .withListener(new PermissionListener() {
                    @Override
                    public void onPermissionGranted(PermissionGrantedResponse response) {
                        // permission is granted
                        openCamera();
                    }

                    @Override
                    public void onPermissionDenied(PermissionDeniedResponse response) {
                        // check for permanent denial of permission
                        if (response.isPermanentlyDenied()) {
                            showSettingsDialog();
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();
    }

    /**
     * Showing Alert Dialog with Settings option
     * Navigates user to app settings
     * NOTE: Keep proper title and message depending on your app
     */
    private void showSettingsDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("Need Permissions");
        builder.setMessage("This app needs permission to use this feature. You can grant them in app settings.");
        builder.setPositiveButton("GOTO SETTINGS", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
                openSettings();
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.show();

    }

    // navigating user to app settings
    private void openSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivityForResult(intent, 101);
    }

    private void openCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, 100);
    }
}
android-runtime-permissions-with-dexter-library
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
  • Tigani

    Thanks guru ..happy new year wish you all the best

    • Thank you Tigani. I wish you the same πŸ™‚

  • mavilla vishnu vardhan

    You are really a saviour. Thanks a lot.

  • Francis Ng’wandu

    Thanks for your help. I real like your tutorials

  • Anushiya Anu

    superb bro…thank you so much…keep posting:)

  • vicky

    hello sir, Can you post some tutorial related to watermarking for types doc.

    • You have to use any image / document processing libraries.

      • vicky

        No.
        I find FFmpeg library but it’s very slow and also updated my APK size more than 16 MB.
        Sir, Can you guide me for better options.

        • Try this library (I haven’t tried) https://github.com/vinaygaba/RubberStamp

          For better solution, consider using ImageMagick or OpenCV.

          • vicky

            Firstly thanks Sir, But sir this lib works only for images. Can you provides any idea or code related this functionality…….

  • Jankari Hindi

    Respected Sir Can You Tell Me Where You are Learning WordPress Website Development And Seo.Please sir Reply

  • Ziigic

    Thank you, I’m waiting for this tutorial.

  • chandan sharma

    Hi . I want to know is there any limitation if we use dexter library instead of normal android program for run time permissions ? Someone one was telling me that use of libraries will make our project heavy so we should only use libraries if we dont have other alternative. Please tell me about this .

  • Pankaj Jangid

    Can It Work On Fragments ?

  • Pawan Soni

    Great Tutorial, but I am facing an issue like when adding more permission it denied that permission even open setting and allow permissions.

    • Can you post the code?

      • Pawan Soni

        private void requestStoragePermission() {
        Dexter.withActivity(this)
        .withPermissions(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.RECEIVE_SMS,
        Manifest.permission.READ_SMS,
        Manifest.permission.SEND_SMS,
        Manifest.permission.READ_PHONE_STATE)
        .withListener(new MultiplePermissionsListener() {
        @Override
        public void onPermissionsChecked(MultiplePermissionsReport report) {
        // check if all permissions are granted
        if (report.areAllPermissionsGranted()) {
        Toast.makeText(getApplicationContext(), “All permissions are granted!”, Toast.LENGTH_SHORT).show();
        }

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

        @Override
        public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) {
        token.continuePermissionRequest();
        }
        }).
        withErrorListener(new PermissionRequestErrorListener() {
        @Override
        public void onError(DexterError error) {
        Toast.makeText(getApplicationContext(), “Error occurred! ” + error.toString(), Toast.LENGTH_SHORT).show();
        }
        })
        .onSameThread()
        .check();
        }

        • Pawan Soni

          It suggest me to open setting but in mobile setting all permission already granted.

          • Strange! Are these permissions added in manifest? Also check in different devices / emulators.

          • Pawan Soni

            Yes!!! Already Added in manifest, but let it be check on other device.
            and thanks again for Tutorial because Run time Permission very big deal ..

          • Yeah! Try Google’s EasyPermissions library too. I have to write an article on that lib too.

          • Pawan Soni

            Thank you so much.I had missed one permission in Manifest.It Working Now.
            This tutorial very Helpful because Without allow All Permission You can not go ahead.
            beacuse before some time It was difficult challange for me. Thanks Again

          • I am glad it solved. Runtime permissions are messy. The libraries are there from the beginning, I wrote the article after so much delay.

  • κ³ μ–‘μ΄λŠ”μ•Όμ˜Ήμ•Όμ˜Ή

    Thank you for great solution! I want share my country developer, so translate this post in my blog, is it possible?

    • Yes you can but please mention this article somewhere in your post.

  • Moh Halim Bimantara

    good

  • This looks promising. I thought about integrating something like this in my own app. Love those libraries which save you time. Going to try this out.

    I think it’s important to have i.e. a settings page, where the user has an overview of the granted permissions.

  • Rushikesh Chaudhari

    can you provide the plugin like that which syntax highlighter you are using in your website for codes.?

  • Dharmendra Mishra

    Code working fine but when we deny Permissions Dialog not showing
    thank you

  • @Murali

    Thank you so much sir,,,,,

  • Muhammad Aamir Akhter

    when i click on open setting the application crash. Please help me