Requesting dangerous permissions on Android
Back in the golden days (Android SDK versions smaller than 23), the only thing
an Android application developer had to do to request permissions for his or
her app was to declare them in the manifest file of their application. For
example, if they wanted to use access fine location information, they would
include the following in their AndroidManifest.xml
file:
However, starting with version 23 and newer of the SDK, things have changed. Android has split the notion of permissions into non-dangerous permissions and dangerous permissions.
Pragmatic takeaway
The important pragmatic take away is that dangerous permissions must be checked, and requested if need be, by the application at run time, even though they must also be declared in the manifest. In addition, it is recommended that an application be able to degrade gracefully if the user declines to grant the permission request. What this means if you are writing an application that must access fine location information and the user denies access to fine location information is a bit unclear. I believe that in some cases there won’t be a graceful way to continue without the necessary permissions.
Checking for permissions when they’re needed
The old way of doing something like registering for location updates looked like this:
The new way needs to look a bit more like the below, with an explicit permission check first:
That doesn’t seem too bad. You’ll find that many IDEs, such as Android Studio, will complain if you forget to explicitly check for the permission first.
But what do you do to ask the user to change those permissions?
Requesting dangerous permissions
If your application needs to access dangerous permissions, you will inevitably want to ask your user to grant you those permissions. This can be done using the ActivityCompat.requestPermissions() method. We can do this using the following code:
What is REQUEST_FINE_LOCATION_ACCESS
? And how do we find out the result of the
request? Well, the result of ActivityCompat.requestPermissions() comes back asynchronously,
and we use our constant REQUEST_FINE_LOCATION_ACCESS
to identify in our
request handler which request we are handling. Speaking of which, how do we
handle these requests? To do this, we override ActivityCompat.onRequestPermissionsResult()
such as with the following code:
If the length of permissions array is 0, we know that the request pipeline was interrupted somewhere and there is nothing for us to do, so we return early. Otherwise, we key off of the permission request code we specified when making the permission request and go from. We get two arrays back, one with the requested permission and the other with the results.
What if they user has previously denied the permissions but there really is a
google reason for them? Once again, there is a solution. This time, in the form
of
ActivityCompat.shouldShowRequestPermissionRationale(). Using this method, we can check before requesting
permissions if a rationale for them should be displayed. If one should be shown,
we can do that, otherwise, we move forward with the request. If we want to
show a rationale, we can update our checkPermissions()
method to the following:
Conclusion
Using the new permissions model for Android, things can definitely get a bit more involved than just listing your needed permissions in the manifest. Knowing how to check for permissions and request permissions is essential. Guides like this one as well as the Android Guide on Working With System Permissions can be helpful resources along the way.
Sample code
If you are interested in the sample code used for this post, you can find it on GitHub.
If you liked this post, you can share it with your followers or follow me on Twitter!