Android Easy Runtime Permissions with Dexter

Expert App Devs
4 min readNov 1, 2021

--

We all know that runtime permission is introduced after Android Marshmallow lets users allow or deny any permission at runtime. Implementation of runtime permissions in android is a hard and complex process for the developers. Developers need to write a lot of code snippets for just single runtime permission.

In this blog, we are going to learn how to implement runtime permission using the Dexter library. Using the library, the permissions can be implemented in less time and efficiently.

This is a basic article about Dexter covering basic features served by the library. Dexter has different types of listener callback, error handling, and many more. You can find more info about Dexter on Dexter’s developer page.

1. Dexter Permissions Library

To work with Dexter, add the library in your build.gradle file

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

1.1 Requesting Single Permission

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

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

> onPermissionDenied() will be called when the permission is declined. You can check whether permission is declined permanently by the user using isPermanentlyDenied() method.

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, add a code for start a camera
}

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

}).check();

1.2 Requesting Multiple Permissions

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

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 allowed or granted
if (report.areAllPermissionsGranted()) {
// do you work now
}

// check for permanent decline of any permission
if (report.isAnyPermissionPermanentlyDenied()) {
// permission denied permanently, navigate user to app settings for granting permissions
}
}

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

1.3 Error Handling

You can also verify and check if any errors occur while implementing the permission request 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 implement Dexter in android projects.

2. Creating New Project

1. Create a new project in Android Studio using the below path. File ⇒ New Project.

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. Add two buttons in your layout file (activity_main.xml) for testing different permission requests.

<?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 add code as per below.

> requestStoragePermission() requests for camera permission.

> requestStoragePermission() requests multiple permissions at once.

> response.isPermanentlyDenied() and report.isAnyPermissionPermanentlyDenied()

checks if the permission is denied permanently by the user. Here we have to redirect the user to the app settings screen by showing a notification.

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 for multiple permissions (storage and location) at once
* This model is used for the multiple requests
* On the permanent decline of permission open a 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 allow by user
if (report.areAllPermissionsGranted()) {
Toast.makeText(getApplicationContext(), “All permissions are granted!”, Toast.LENGTH_SHORT).show();
}

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

@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken permissionToken) {
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 is used for the single request permission
* Once the permission is granted, you can start the camera
* On permanent decline opens a 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 decline of permission
if (response.isPermanentlyDenied()) {
showSettingsDialog();
}
}.check();
}

/**
* Showing an Alert Dialog with an option of opening a setting
* Redirect user to app settings
* NOTE: Add proper title and message depending on your features and app
*/
private void showSettingsDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(“Need Permissions”);
builder.setPositiveButton(“GOTO SETTINGS”, new DialogInterface.OnClickListener() {
@Override
dialogInterface.cancel();
openSettings();
}
});
builder.setNegativeButton(“Cancel”, new DialogInterface.OnClickListener() {
@Override

dialogInterface.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);
}
}

--

--

Expert App Devs

We are a 13 year old bespoke iOS & Android app development company from India. Find the latest updates & insights on mobile apps. https://www.expertappdevs.com