Working with Runtime Permissions - Android

How to implement Runtime Permissions in Android Marshmallow 6.0

For app developers and publishers, the biggest change they will need to integrate and test is how Android will now handle app permissions. If you are unfamiliar with permissions in Android, when an app is downloaded from Google Play, the user can see what that app is allowed to do with the phone. Some apps request permission to access user’s contacts or calendar, Wi-Fi and cellular data, camera access and so forth.


Before we start, Learn What is Android Runtime Permission?

How to make your application support new Runtime Permission

Now it's time to make our application support new Runtime Permission perfectly. Start with setting compileSdkVersion and targetSdkVersion to 23 (or higher) in app/build.gradle file.
android {
    compileSdkVersion 23
    ...

    defaultConfig {
        ...
        targetSdkVersion 23
        ...
}

Declare permissions in AndroidManifest.xml

It is required to declare the permission in AndroidManifest.xml file in order for app to ask for the permission.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    ...
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    ...
    <application
        ...
    </application>
    ...
</manifest>

How to ask for the runtime permission programatically?

Now the question arises, how an application can request for or get permission? Or rather, what workflow the developer should follow to request and get permission for the app? Let us have a look.

In this example, we try to get write storage permission with a function below.
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                //Show Information about why you need the permission
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("Need Storage Permission");
                builder.setMessage("This app needs storage permission.");
                builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_CONSTANT);
                    }
                });
                builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                builder.show();
            } else if (permissionStatus.getBoolean(Manifest.permission.WRITE_EXTERNAL_STORAGE,false)) {
                //Previously Permission Request was cancelled with 'Dont Ask Again',
                // Redirect to Settings after showing Information about why you need the permission
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("Need Storage Permission");
                builder.setMessage("This app needs storage permission.");
                builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                        sentToSettings = true;
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", getPackageName(), null);
                        intent.setData(uri);
                        startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
                        Toast.makeText(getBaseContext(), "Go to Permissions to Grant Storage", Toast.LENGTH_LONG).show();
                    }
                });
                builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                builder.show();
            } else {
                //just request the permission
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_CONSTANT);
            }
 
            SharedPreferences.Editor editor = permissionStatus.edit();
            editor.putBoolean(Manifest.permission.WRITE_EXTERNAL_STORAGE,true);
            editor.commit();
 
 
} else {
	//You already have the permission, just go ahead.
    proceedAfterPermission();
}

Explanation :

We checked for permission with checkSelfPermission() Method to check if the app already has permission to write on external storage. If it has then continue to else part, otherwise go to next step.

Here we used shouldShowRequestPermissionRationale() method to check if we should show the explanation for the permission or not, if this returns true then we showed an alert dialog with explanation, and on the positive button click we requested the permission. If shouldShowRequestPermissionRationale returns false then we requested permission straight forward.




We have successfully requested permission so far. We just need to override the method onRequestPermissionsResult to receive the result. In that method first we checked the requested code with our declared constant requestCode == EXTERNAL_STORAGE_PERMISSION_CONSTANT then checked if length of grantResult is greater than 0, so that it contains the user’s decision, then we cheked if the value of 0 index of the grant result, if the value is equal to PackageManager.PERMISSION_GRANTED then it means that the user has authorised the permission and we can continue our work, otherwise in the else part we can again request for permission with explanation.




Add SharedPreferences, think of a situation where the user has denied permission by checking “Never Ask Again”. In that scenario the shouldShowRequestPermissionRationale method will return false and requestPermissions method will do just nothing. So we need to remember whether we have priorly requested for permission or not, even after the app restarts. For that purpose we will use SharedPreferences, we will use the permission string as the key and boolean true or false as value.


Take a look at What is Android Runtime Permission to know more about what is Runtime Permissions.

References:


Thanks for reading this article. Hope you would have liked it!. Please share and subscribe to this blog to support. 

Pragnesh Ghoda

A forward-thinking developer offering more than 8 years of experience building, integrating, and supporting android applications for mobile and tablet devices on the Android platform. Talks about #kotlin and #android

Post a Comment

Please let us know about any concerns or query.

Previous Post Next Post

Contact Form