When to request permission at runtime for Android Marshmallow 6.0?

17,064

Solution 1

In general, request needed permissions it as soon as you need them. This way you can inform the user why you need the permission and handle permission denies much easier.

Think of scenarios where the user revokes the permission while your app runs: If you request it at startup and never check it later this could lead to unexpected behaviour or exceptions.

Solution 2

This is worked for me !!! In Your Splash Activity of your application do the following,

1) Declare an int variable for request code,

private static final int REQUEST_CODE_PERMISSION = 2;

2) Declare a string array with the number of permissions you need,

 String[] mPermission = {Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
 Manifest.permission.ACCESS_FINE_LOCATION,
 Manifest.permission.WRITE_EXTERNAL_STORAGE};

3) Next Check the condition for runtime permission on your onCreate method,

try {
            if (ActivityCompat.checkSelfPermission(this, mPermission[0])
                    != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[1])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[2])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[3])
                            != MockPackageManager.PERMISSION_GRANTED) {

                ActivityCompat.requestPermissions(this,
                        mPermission, REQUEST_CODE_PERMISSION);

              // If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

4) Now Declare onRequestPermissionsResult method to check the request code,

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Log.e("Req Code", "" + requestCode);
        if (requestCode == REQUEST_CODE_PERMISSION) {
            if (grantResults.length == 4 &&
                    grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[3] == MockPackageManager.PERMISSION_GRANTED) {

               // Success Stuff here

            }
        }

    }

Solution 3

Do like this

private static final int  REQUEST_ACCESS_FINE_LOCATION = 111;

In your onCreate

boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermissionLocation) {
        ActivityCompat.requestPermissions(ThisActivity.this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_ACCESS_FINE_LOCATION);
    }

then check result

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {

        case REQUEST_ACCESS_FINE_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();

                //reload my activity with permission granted
                finish();
                startActivity(getIntent());

            } else
            {
                Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }

    }

}

Solution 4

In my opinion, there is no one correct answer to your question. I strongly suggest you to look at this official permissions patterns page.

Couple of things suggested by Google :

"Your permissions strategy depends on the clarity and importance of the permission type you are requesting. These patterns offer different ways of introducing permissions to the user."

"Critical permissions should be requested up-front. Secondary permissions may be requested in-context."

"Permissions that are less clear should provide education about what the permission involves, whether done up-front or in context."

This illustration might give you better understanding.

Maybe the most crucial thing here is that whether you ask the permission up-front or in the context, you should always keep in mind that these permissions can be revoked anytime by the user (e.g. your app is still running, in background).

You should make sure that your app doesn't crash just because you asked the permission on the very beginning of the app and assumed that user didn't change his/her preference about that permission.

Solution 5

    Android Easy Runtime Permissions with Dexter:
    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();
Share:
17,064
Pankaj
Author by

Pankaj

I like to code each n every day and develop some good mobile app.

Updated on June 25, 2022

Comments

  • Pankaj
    Pankaj about 2 years

    I am testing my app on Marshmallow 6.0 and it's getting force closed for the android.permission.READ_EXTERNAL_STORAGE, even if it is defined in the Manifest already. Somewhere I have read that if I request permission at runtime then it would not force close your application. I have read this android document also, which is for requesting runtime permission.

    So, I came to know that we can request a permission like below which is mentioned in the android document.

    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(thisActivity,
                    Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {
    
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                Manifest.permission.READ_CONTACTS)) {
    
            // Show an expanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
    
        } else {
    
            // No explanation needed, we can request the permission.
    
            ActivityCompat.requestPermissions(thisActivity,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    
            // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    }
    

    The above code has a callback method onRequestPermissionsResult which gets the result.

    @Override
    public void onRequestPermissionsResult(int requestCode,
            String permissions[], int[] grantResults) {
        switch (requestCode) {
    
         }
    }
    

    My question is where to exactly request the permission to user? Should we use the requesting permission at start of the app or should we do it as when the permission is required?

  • Pankaj
    Pankaj over 8 years
    So your saying I have to request permission when we needed not at start up.
  • Jörn Buitink
    Jörn Buitink over 8 years
    Yes. You don't know if the user revokes the permission during the runtime of you app.
  • Pankaj
    Pankaj over 8 years
    Didn't get your code your saying do your stuff here at two places. There should be only one place to do my stuff not at two and how onRequestPermissionsResult would be called???
  • Nanda Gopal
    Nanda Gopal over 8 years
    Sorry for that, just do the code in onRequestPermissionResult and then tell me ur result
  • xanexpt
    xanexpt over 8 years
    this is my opinion too, there is no correct awnser for this question, the guys from ux should decide this depending on the product
  • not2qubit
    not2qubit over 7 years
    You are lacking comments to your code, what are you doing differently in your answer? and your previous answer?