We all know that Android Marshmallow introduced runtime permissions that allow users to allow or deny all permissions at run time.
In this article, we will simplify obtaining permission to use permissions using the Dexter library. Using this library, permissions will be granted in just a few minutes.
1. Use the Dexter library
To use the Dexter library, add dependency to the project’s app / build.gradle :
1 2 3 4 5 | dependencies { // Dexter runtime permissions implementation 'com.karumi:dexter:4.2.0' } |
1.1 Request a Permission
To request a permission, you can use the withPermission () function by passing the required permission. You also need the PermissionListener callback to get permission status.
> onPermissionGranted () will be called after permission is granted. > onPermissionDenied () will be called when permission is denied. You can check if the permission is permanently denied or not by using the answer.isPternalDenied () condition.
The following code snippet will require using the CAMERA permission:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 Request multiple Permission
To request multiple permissions at once, you can use the withPermissions () function.
The following code snippet will require using permission STORAGE and LOCATION :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 occurred
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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(); |
2. Create a new Projetc
1. Android Studio ⇒ File ⇒ New Project ⇒ Basic Activity
- Add the Dexter library to the build.gradle file
1 2 3 4 5 6 7 8 9 | 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' } |
- Open the Main Activity layout: activity_main.xml and content_main.xml
content_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?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> |
- MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | 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); } } |