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.
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); } }
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
Thanks guru ..happy new year wish you all the best
Thank you Tigani. I wish you the same 🙂
You are really a saviour. Thanks a lot.
You are welcome 🙂
Thanks for your help. I real like your tutorials
Cheers!
superb bro…thank you so much…keep posting:)
Yup I’ll do my best.
hello sir, Can you post some tutorial related to watermarking for types doc.
You have to use any image / document processing libraries.
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.
Firstly thanks Sir, But sir this lib works only for images. Can you provides any idea or code related this functionality…….
Respected Sir Can You Tell Me Where You are Learning WordPress Website Development And Seo.Please sir Reply
There is not just one website to learn WordPress or SEO. I can suggest you these.
https://www.shoutmeloud.com/wordpress-guide
http://www.wpbeginner.com/category/wp-tutorials/
Thank you, I’m waiting for this tutorial.
you are welcome 🙂
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 .
Yes libraries makes the app size bigger but Dexter is lightweight. You need to use proper ProGuard rules to minimize the apk size while building it in release mode.
https://github.com/Karumi/Dexter/blob/master/dexter/proguard-rules.pro
Can It Work On Fragments ?
It should be.
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?
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();
}
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.
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.
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.
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.
can you provide the plugin like that which syntax highlighter you are using in your website for codes.?
You can try these plugins in your WordPress website.
https://wordpress.org/plugins/crayon-syntax-highlighter/
https://wordpress.org/plugins/syntaxhighlighter/
and which one your are using.? I am asking because I like your theme.
I am using SyntaxHighlighter. Mine is customized.
Code working fine but when we deny Permissions Dialog not showing
thank you
I also have the same thing.
I am also facing the same problem
Thank you so much sir,,,,,
You are welcome 🙂
when i click on open setting the application crash. Please help me
Check the LogCat for errors.
sir, this was really a great job, but i m having little problem.
I have added seven permissions
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,
Manifest.permission.VIBRATE,
Manifest.permission.RECORD_AUDIO
but it ask for only two permission audio & storage and even after giving permission it show dialog to go to setting every time i open the app please help me sir
Request only the necessary permissions. INTERNET is not runtime permission and not needed to request it.
You can see list of dangerous permissions here.
https://developer.android.com/guide/topics/permissions/overview#permission-groups
this was really great 👏👏👏
(please read my previous question before reading this)
sir i used below logic to prevent app from asking permission
// check for permanent denial of any permission
if (report.isAnyPermissionPermanentlyDenied()) {
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(“PERMISSION_PERMANENTLY_DENIED”,true);
editor.apply();
if(!sharedPref.getBoolean(“PERMISSION_PERMANENTLY_DENIED”,false)){
// show alert dialog navigating to Settings
showSettingsDialog();
}
}
should i use it? because first because at first time app shown a new type of dialog “screen overlay detected”
what would be consequences if i use above code on performance
Preference manager is not necessary when Dexter is used. It can handle it the first time case and denied.
sir i had tried on different devices but that not happened..that why i had to use this logic..
hi sir how can we handle following case in dexter :-
Step 1: Opened app and gave all the necessary permissions
Step 2: Clicked Home button(So the app is in background)
Step 3: Manually changed the permissions in the Settings
Step 4: Launched the app from multitasks, now it crashes because of app context becomes invalid
normally we use onRequestPermissionsResult. but in dexter how can we handle this ??
write all permission code in onResume
Although i used dexter, after clicking allow , my location didnt turned on, i had to go manually to the settings and turned on my location. I am using naughat. Why is this hapening sir ?? Am i doing something wrong? Your answer would be highly appeciable 🙂 Thanks.
very nice sir its so easy thankio..
sir i have a little error that is
Error: The processing instruction target matching “[xX][mM][lL]” is not allowed.
Here i have use Dexter permission is granted on location update but it does not show location on lolipop with i am not able to find whether permission issue or location update call back result is not getting … If any suggestions to please help me …
Permissions at run time only appears on Marshmallow to higher versions. If you have declared permissions in manifest then on Lollipop it will automatically grant permissions while installing the app.
how can i onn my mobile data from third my app
i.e how to on mobile data programmatically
It’s nice to see a disclaimer like yours!
I got some memory leakage after integrating this..
Thanks for the post…
Nice post
I think you don’t need startActivityForResult(intent, 101); because you don’t handle the result
Great explanation, but I have a question, How can I update my UI after all the permissions are granted? There is any callback to listen to the result?
Yes, below is callback
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
// check if all permissions are granted
if (report.areAllPermissionsGranted()) {
// do you work now
}
Sir, Its Not working on Deny of Permission the Dialog Closes, Setting Option Is not Comming
Checked With your Apk on Redmi 7a, Redmi 4, redmi 4 A , Emulator.
I also have the issue, please update if you have found the solution
public void onPermissionDenied(PermissionDeniedResponse response)
{showSettingsDialog();}
Remove the if-statement, the permission was already denied.
Recommended artice