Convert Figma logo to code with AI

Karumi logoDexter

Android library that simplifies the process of requesting permissions at runtime.

5,232
671
5,232
34

Top Related Projects

A declarative API to handle Android runtime permissions.

Android runtime permissions powered by RxJava2

Simplify Android M system permissions

Easy check permission library for Android Marshmallow

Quick Overview

Dexter is an Android library that simplifies the process of requesting runtime permissions. It provides an easy-to-use API for handling permission requests, making it more convenient for developers to implement and manage permissions in their Android applications.

Pros

  • Simplifies the complex Android runtime permission system
  • Provides a clean and intuitive API for handling permissions
  • Supports chaining multiple permission requests
  • Offers customizable error handling and UI for permission requests

Cons

  • Adds an additional dependency to the project
  • May require some learning curve for developers new to the library
  • Limited to Android platform only
  • Maintenance and updates depend on the library maintainers

Code Examples

  1. Requesting a single permission:
Dexter.withContext(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(object : PermissionListener {
        override fun onPermissionGranted(response: PermissionGrantedResponse) {
            // Permission granted, proceed with camera-related functionality
        }
        override fun onPermissionDenied(response: PermissionDeniedResponse) {
            // Permission denied, handle accordingly
        }
        override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest, token: PermissionToken) {
            token.continuePermissionRequest()
        }
    }).check()
  1. Requesting multiple permissions:
Dexter.withContext(this)
    .withPermissions(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_CONTACTS,
        Manifest.permission.RECORD_AUDIO
    ).withListener(object : MultiplePermissionsListener {
        override fun onPermissionsChecked(report: MultiplePermissionsReport) {
            if (report.areAllPermissionsGranted()) {
                // All permissions granted
            }
        }
        override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) {
            token.continuePermissionRequest()
        }
    }).check()
  1. Continuous permission checking:
Dexter.withContext(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(object : PermissionListener {
        override fun onPermissionGranted(response: PermissionGrantedResponse) {
            // Permission granted
        }
        override fun onPermissionDenied(response: PermissionDeniedResponse) {
            if (response.isPermanentlyDenied) {
                // Navigate to app settings
            }
        }
        override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest, token: PermissionToken) {
            token.continuePermissionRequest()
        }
    }).onSameThread().check()

Getting Started

  1. Add the Dexter dependency to your app's build.gradle file:
dependencies {
    implementation 'com.karumi:dexter:6.2.3'
}
  1. Initialize Dexter in your Activity or Fragment:
import com.karumi.dexter.Dexter
import com.karumi.dexter.listener.PermissionListener
import com.karumi.dexter.listener.single.PermissionListener

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

        // Use Dexter to request permissions as shown in the code examples above
    }
}

Competitor Comparisons

A declarative API to handle Android runtime permissions.

Pros of PermissionsDispatcher

  • Uses annotation processing, which can lead to better compile-time safety
  • Generates boilerplate code, reducing the amount of manual coding required
  • Supports special permissions like system alert window and write settings

Cons of PermissionsDispatcher

  • Requires more setup and configuration compared to Dexter
  • May increase build times due to annotation processing
  • Less flexible for complex permission scenarios

Code Comparison

PermissionsDispatcher:

@RuntimePermissions
class MainActivity : AppCompatActivity() {
    @NeedsPermission(Manifest.permission.CAMERA)
    fun showCamera() {
        // Camera permission granted
    }
}

Dexter:

Dexter.withActivity(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(object : PermissionListener {
        override fun onPermissionGranted(response: PermissionGrantedResponse) {
            // Camera permission granted
        }
    }).check()

PermissionsDispatcher uses annotations to generate code, while Dexter employs a more fluent API. PermissionsDispatcher requires less boilerplate but may be less flexible for complex scenarios. Dexter offers a more straightforward setup and greater flexibility but requires more manual coding.

Android runtime permissions powered by RxJava2

Pros of RxPermissions

  • Integrates seamlessly with RxJava, allowing for reactive programming patterns
  • Lightweight and focused solely on runtime permissions
  • Supports handling multiple permissions in a single request

Cons of RxPermissions

  • Requires knowledge of RxJava, which may have a steeper learning curve
  • Limited to Android 6.0 (API 23) and above
  • Less comprehensive documentation compared to Dexter

Code Comparison

Dexter:

Dexter.withActivity(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(new PermissionListener() {
        @Override public void onPermissionGranted(PermissionGrantedResponse response) { /* ... */ }
        @Override public void onPermissionDenied(PermissionDeniedResponse response) { /* ... */ }
        @Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) { /* ... */ }
    }).check();

RxPermissions:

RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { /* ... */ } else { /* ... */ }
    });

The code comparison shows that RxPermissions offers a more concise syntax, especially when used with lambda expressions. However, Dexter provides more detailed callbacks for different permission states, which can be beneficial for handling complex permission scenarios.

Simplify Android M system permissions

Pros of EasyPermissions

  • Simpler API with fewer methods, making it easier to learn and implement
  • Supports both Activity and Fragment contexts out of the box
  • Integrates well with Android's native permission system

Cons of EasyPermissions

  • Less granular control over permission requests compared to Dexter
  • Fewer customization options for permission rationale dialogs
  • Limited support for handling permanent permission denials

Code Comparison

Dexter:

Dexter.withActivity(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(new PermissionListener() {
        @Override public void onPermissionGranted(PermissionGrantedResponse response) {}
        @Override public void onPermissionDenied(PermissionDeniedResponse response) {}
        @Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {}
    }).check();

EasyPermissions:

EasyPermissions.requestPermissions(
    this,
    "This app needs access to your camera.",
    RC_CAMERA_PERM,
    Manifest.permission.CAMERA);

Summary

EasyPermissions offers a more straightforward approach to handling Android runtime permissions, with a simpler API and better integration with Android's native permission system. However, Dexter provides more fine-grained control and customization options, making it suitable for complex permission scenarios. The choice between the two libraries depends on the specific requirements of your project and the level of control you need over the permission request process.

Easy check permission library for Android Marshmallow

Pros of TedPermission

  • Supports both Kotlin and Java, offering flexibility for different Android development preferences
  • Provides a simpler API with fewer method calls required for basic permission requests
  • Includes a built-in rationale dialog, reducing the need for custom implementations

Cons of TedPermission

  • Less extensive documentation compared to Dexter
  • Fewer advanced features for complex permission scenarios
  • Limited customization options for the rationale dialog

Code Comparison

TedPermission:

TedPermission.create()
    .setPermissions(Manifest.permission.CAMERA)
    .check()

Dexter:

Dexter.withContext(this)
    .withPermission(Manifest.permission.CAMERA)
    .withListener(new PermissionListener() {
        // Implement callback methods
    }).check();

TedPermission offers a more concise syntax for basic permission requests, while Dexter provides more granular control through its listener-based approach. TedPermission's API is generally simpler and more straightforward, making it easier for developers to implement basic permission handling. However, Dexter's more verbose syntax allows for greater flexibility in handling complex permission scenarios and customizing behavior.

Both libraries aim to simplify Android runtime permissions, but they cater to different developer preferences and use cases. TedPermission is more suitable for projects requiring quick and simple permission handling, while Dexter excels in scenarios demanding fine-grained control and extensive customization.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Karumi logo Dexter Build Status Maven Central Android Arsenal

This project is no longer under active development. If you are looking for an Android library to be able to request Android permissions in runtime take a look here

Dexter is an Android library that simplifies the process of requesting permissions at runtime.

Android Marshmallow includes a new functionality to let users grant or deny permissions when running an app instead of granting them all when installing it. This approach gives the user more control over applications but requires developers to add lots of code to support it.

Dexter frees your permission code from your activities and lets you write that logic anywhere you want.

Screenshots

Demo screenshot

Usage

Dependency

Include the library in your build.gradle

dependencies{
    implementation 'com.karumi:dexter:6.2.3'
}

To start using the library you just need to call Dexter with a valid Context:

public MyActivity extends Activity {
	@Override public void onCreate() {
		super.onCreate();
		Dexter.withContext(activity)
			.withPermission(permission)
			.withListener(listener)
			.check();
	}
}

Single permission

For each permission, register a PermissionListener implementation to receive the state of the request:

Dexter.withContext(this)
	.withPermission(Manifest.permission.CAMERA)
	.withListener(new PermissionListener() {
		@Override public void onPermissionGranted(PermissionGrantedResponse response) {/* ... */}
		@Override public void onPermissionDenied(PermissionDeniedResponse response) {/* ... */}
		@Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {/* ... */}
	}).check();

To make your life easier we offer some PermissionListener implementations to perform recurrent actions:

  • BasePermissionListener to make it easier to implement only the methods you want. Keep in mind that you should not call super methods when overriding them.
  • DialogOnDeniedPermissionListener to show a configurable dialog whenever the user rejects a permission request:
PermissionListener dialogPermissionListener =
	DialogOnDeniedPermissionListener.Builder
		.withContext(context)
		.withTitle("Camera permission")
		.withMessage("Camera permission is needed to take pictures of your cat")
		.withButtonText(android.R.string.ok)
		.withIcon(R.mipmap.my_icon)
		.build();
  • SnackbarOnDeniedPermissionListener to show a snackbar message whenever the user rejects a permission request:
PermissionListener snackbarPermissionListener =
	SnackbarOnDeniedPermissionListener.Builder
		.with(view, "Camera access is needed to take pictures of your dog")
		.withOpenSettingsButton("Settings")
        .withCallback(new Snackbar.Callback() {
            @Override
            public void onShown(Snackbar snackbar) {
                // Event handler for when the given Snackbar is visible
            }
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                // Event handler for when the given Snackbar has been dismissed
            }
        }).build();
  • CompositePermissionListener to compound multiple listeners into one:
PermissionListener snackbarPermissionListener = /*...*/;
PermissionListener dialogPermissionListener = /*...*/;
PermissionListener compositePermissionListener = new CompositePermissionListener(snackbarPermissionListener, dialogPermissionListener, /*...*/);

Multiple permissions

If you want to request multiple permissions you just need to call withPermissions and register an implementation of MultiplePermissionsListener:

Dexter.withContext(this)
	.withPermissions(
		Manifest.permission.CAMERA,
		Manifest.permission.READ_CONTACTS,
		Manifest.permission.RECORD_AUDIO
	).withListener(new MultiplePermissionsListener() {
	    @Override public void onPermissionsChecked(MultiplePermissionsReport report) {/* ... */}
	    @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {/* ... */}
	}).check();

The MultiplePermissionsReport contains all the details of the permission request like the list of denied/granted permissions or utility methods like areAllPermissionsGranted and isAnyPermissionPermanentlyDenied.

As with the single permission listener, there are also some useful implementations for recurring patterns:

  • BaseMultiplePermissionsListener to make it easier to implement only the methods you want. Keep in mind that you should not call super methods when overriding them.
  • DialogOnAnyDeniedMultiplePermissionsListener to show a configurable dialog whenever the user rejects at least one permission:
MultiplePermissionsListener dialogMultiplePermissionsListener =
	DialogOnAnyDeniedMultiplePermissionsListener.Builder
		.withContext(context)
		.withTitle("Camera & audio permission")
		.withMessage("Both camera and audio permission are needed to take pictures of your cat")
		.withButtonText(android.R.string.ok)
		.withIcon(R.mipmap.my_icon)
		.build();
  • SnackbarOnAnyDeniedMultiplePermissionsListener to show a snackbar message whenever the user rejects any of the requested permissions:
MultiplePermissionsListener snackbarMultiplePermissionsListener =
	SnackbarOnAnyDeniedMultiplePermissionsListener.Builder
		.with(view, "Camera and audio access is needed to take pictures of your dog")
		.withOpenSettingsButton("Settings")
        .withCallback(new Snackbar.Callback() {
            @Override
            public void onShown(Snackbar snackbar) {
                // Event handler for when the given Snackbar is visible
            }
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                // Event handler for when the given Snackbar has been dismissed
            }
        })
		.build();
  • CompositePermissionListener to compound multiple listeners into one:
MultiplePermissionsListener snackbarMultiplePermissionsListener = /*...*/;
MultiplePermissionsListener dialogMultiplePermissionsListener = /*...*/;
MultiplePermissionsListener compositePermissionsListener = new CompositeMultiplePermissionsListener(snackbarMultiplePermissionsListener, dialogMultiplePermissionsListener, /*...*/);

Handling listener threads

If you want to receive permission listener callbacks on the same thread that fired the permission request, you just need to call onSameThread before checking for permissions:

Dexter.withContext(context)
	.withPermission(permission)
	.withListener(listener)
	.onSameThread()
	.check();

Showing a rationale

Android will notify you when you are requesting a permission that needs an additional explanation for its usage, either because it is considered dangerous, or because the user has already declined that permission once.

Dexter will call the method onPermissionRationaleShouldBeShown implemented in your listener with a PermissionToken. It's important to keep in mind that the request process will pause until the token is used, therefore, you won't be able to call Dexter again or request any other permissions if the token has not been used.

The most simple implementation of your onPermissionRationaleShouldBeShown method could be:

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

Error handling

If you think there is an error in your Dexter integration, just register a PermissionRequestErrorListener when calling Dexter:

Dexter.withContext(context)
	.withPermission(permission)
	.withListener(listener)
	.withErrorListener(new PermissionRequestErrorListener() {
		@Override public void onError(DexterError error) {
			Log.e("Dexter", "There was an error: " + error.toString());
		}
	}).check();

The library will notify you when something bad happens. In general, it is a good practice to, at least, log every error Dexter may throw but is up to you, the developer, to do that.

IMPORTANT: Remember to follow the Google design guidelines to make your application as user-friendly as possible.

Permission dialog not being shown

If you are using the MultiplePermissionsListener and you don't see the permission dialog the second time the permission is checked review your configuration. Keep in mind you need to let Dexter know the rationale you can show was closed or not by calling token?.continuePermissionRequest(). If you don't do this, the next time the permission is requested, the OS dialog asking for this permission won't be shown. You can find more information about this in here. This is an example of how a multiple permission request should be implemented:

button.setOnClickListener {
    Dexter.withContext(this@MainActivity)
                        .withPermissions(
                            Manifest.permission.ACCESS_COARSE_LOCATION
                            ,Manifest.permission.ACCESS_FINE_LOCATION)
                        .withListener(object: MultiplePermissionsListener {
                            override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
                                report?.let {
                                    if(report.areAllPermissionsGranted()){
                                        toast("OK")
                                    }
                                }
                            }
                            override fun onPermissionRationaleShouldBeShown(
                                permissions: MutableList<PermissionRequest>?,
                                token: PermissionToken?
                            ) {
                                // Remember to invoke this method when the custom rationale is closed
                                // or just by default if you don't want to use any custom rationale.
                                token?.continuePermissionRequest()
                            }
                        })
                        .withErrorListener {
                            toast(it.name)
                        }
                        .check()
}

Caveats

  • For permissions that did not exist before API Level 16, you should check the OS version and use ContextCompat.checkSelfPermission. See You Cannot Hold Non-Existent Permissions.
  • Don't call Dexter from an Activity with the flag noHistory enabled. When a permission is requested, Dexter creates its own Activity internally and pushes it into the stack causing the original Activity to be dismissed.
  • Permissions SYSTEM_ALERT_WINDOW and WRITE_SETTINGS are considered special by Android. Dexter doesn't handle those and you'll need to request them in the old fashioned way.

Contributors

Thank you all for your work!


Carlos Morera de la Chica

Alex Florescu

Pedro Veloso

Dion Segijn

Christian Panadero

Vignesh

Andy French

Bernat Borrás Paronella

Bastien Paul

Bas Broek

Bartek Lipinski

emmano

Konrad Morawski

Hrant Alaverdyan

Carla

Pavel Stepanov

Emmett Wilson

Max

Al B.

Vladislav Bauer

Jc Miñarro

handrenliang

jcruzsousa

lzdon

Do you want to contribute?

Feel free to add any useful feature to the library, we will be glad to improve it with your help.

Keep in mind that your PRs must be validated by Travis-CI. Please, run a local build with ./gradlew checkstyle build test before submiting your code.

Libraries used in this project

License

Copyright 2015 Karumi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.