Android permission handling done right with Kotlin
Permission handling should be simple, but not the case in Android. Or at least before you know a lot about it. This article aims to solve that problem. And we will use Anko
here to make it better.
1. Official documentation
This is where you can find the official solution. It explains well but it depends on you how you shape your interactive model. Let’s see how google designs this model.
2. Google’s model
Below is the official code.
1 | // Here, thisActivity is the current activity |
The code is easy to read:
- Check whether we got the permission or not.
- If yes, we go to the
else
:Permission has already been granted
case. - If no, two sub-cases here:
- show permission rationale, then ask permission again
- no need to show permission rationale
The key part here is the usage of shouldShowRequestPermissionRationale
.
And when a user runs through the flow:
The user will get the ask-for-permission-dialog right away. If he grants it, then all fine. If he denies it, then the next time it will then trigger the shouldShowRequestPermissionRationale
block.
3. Problem
The problem is what about as soon as the user sees the ask-for-permission-dialog, he just denies, close the app and uninstall? Because it seems it’s something like a system notification that we want to just use some feature without permission?
Because
shouldShowRequestPermissionRationale
won’t returntrue
if this is the first time the user asks for permission.
And if you use this to show your real rationale, the code seems very clean, something like if shouldShowRequestPermissionRationale then showReason
. Then you will be surprised to see that it won’t work for the first time.
Things will become more interesting when the user denies after the 2nd time. The 3rd time there will be a Never ask again
checkbox. And how to handle that after the user tick that option?
And when this is a very important permission to this app, we want some better model to handle it.
4. Design thinking
Always asks for permission when the user just trigger the feature, try not to ask for many permissions at the start. Because when the user just needs it, in that context, it will make them feel more comfortable to grant you the permission. And actually, it will be quite easy, and Kotlin will make it easier, which we will see later.
5. Our model
In the app. First, we check the permission, and we execute the tasks if we got the permission. And here is how we handle the case when the permission is not granted.
- We always show a dialog to explain why we need the permission.
- Then we try to request the permission.
- Success case: We get the permission, cool, let’s go on.
- Failure case: We will display some further explanation and try to request again, or just stop because the user can press the button again to trigger the whole procedure again
- NeverAskAgain case: We need to route the user to application settings page and let them enable it there because this is the only way. And besides that, we will show an explanation to tell the user what will happen.
6. Code blocks
With the above ideas in mind, let’s see how to implement this.
6.1 How to check the permission
1 | if (isPermissionGranted(SEND_SMS)) { |
Something needs to know here, you don’t need to handle the API case where Google makes a change to the request model. import android.support.v4.content.ContextCompat.checkSelfPermission
will handle it for you. If the above run under an older device (<= API 23), it will return true. So you can always execute the permission without a problem.
6.2 Show permission rationale
When the permission is not granted, inside the above else
block, add this code
1 | showPermissionReasonAndRequest( |
We will show the reason, and after the user press yes
, we will ask for permission and dismiss the alert
if user presses no
button.
6.3 Handle the three cases
You will see that we haven’t used that shouldShowRequestPermissionRationale
. When will we use it? Well, we will only use it to check the never ask again
option has been ticked or not.
So after the user responds to your request. It will trigger onRequestPermissionsResult
method, and this is where you can handle that.
1 | override fun onRequestPermissionsResult( |
And this is how you route the user to the application setting screen.
1 | val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, |
Then everything should behave as expected.
6. What about using some DSL to make it better
Although the above code works, can we make it any better? What about inside that onRequestPermissionsResult()
, we can write something like this:
1 | override fun onRequestPermissionsResult( |
It behaves exactly like the previous one. But in a more declarative and readable way. Even better, you can now reuse it in any activity
. Wait for my next blog, we will see how easily Kotlin will enable us to do something fancy like this. :)
Thanks for reading!
Follow me (albertgao) on twitter, if you want to hear more about my interesting ideas.