Better permissions on Android
Permissions request dialogs are a vital part of user’s experience on the app. When a user installs an application for the first time they may or may not be clear of what the app does and why the app requires a certain set of permissions for its functionality.
Many applications show a permission request dialog and a user can choose to grant or deny a permission. Often a user may deny a certain permission which may be required for the core functionality of the app.
Well, why are permission rationale dialog important?
They offer the user a clear explanation on why the permission is required which may have been unclear previously when the user had denied the permission.
In this article we’ll cover how to handle cases where a user has previously denied a permission and present them with a rationale or a reason on why the user should grant the permission by using best practices and taking advantage of shouldShowRequestPermissionRationale. Let’s get started!
In this example we’ll be making a simple app in Kotlin which requests permissions and presents the user with a rationale for granting a denied permission. We’ll take a case where the app requires READ_CONTACTS permission from the user.
Step 1: Define the permission in the Manifest
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Step 2: Define a function that checks for the permission
private fun checkContactsPermission() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS) !=
PackageManager.PERMISSION_GRANTED
) {
// Check if permission is not granted
Log.d(TAG, "Permission for contacts is not granted")
// This condition only becomes true if the user has denied the permission previously
if (shouldShowRequestPermissionRationale(android.Manifest.permission.READ_CONTACTS)) {
showRationaleDialog(getString(R.string.rationale_title),
getString(R.string.rationale_desc),
android.Manifest.permission.READ_CONTACTS,
REQUEST_CONTACTS_STATE)
} else {
// Perform a permission check
Log.d(TAG, "Checking permission")
requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS),REQUEST_CONTACTS_STATE)
}
} else {
// Permission is already granted, do your magic here!
}
}
Here the code will perform a check if the read contacts permission is granted or not. The following cases will occur:
- First time user who is opening the app will be presented with a standard request permission dialog.
- A user who has denied the permission previously will be presented with a rationale dialog.
- User has granted the permission.
Step 3: Define your function for showing a rationale dialog
We can acheive this with an AlertDialog as shown in the below function
private fun showRationaleDialog(title: String, message: String, permission: String, requestCode: Int) {
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setTitle(title)
.setMessage(message)
.setPositiveButton("Ok", { dialog, which ->
requestPermissions(arrayOf(permission), requestCode)
})
builder.create().show()
}
We’ll also add strings for the dialog. In this example our sample app needs read contacts permission for suggesting connections or people the user may know.
strings.xml
<string name="rationale_title">We need permission to read your contacts</string>
<string name="rationale_desc">This app relies on read access to your contacts.
We require access to this permission to find your contacts in our database and suggest people you may know.
We will not store any contact info in our data base if they are not a part of our platform.
For further info read our privacy policy.</string>
Step 4: Let’s handle the permission results
We’ll display a Toast message once permission has been granted or denied by overriding onPermissionResults()
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>,
grantResults:IntArray) {
when (requestCode) {
REQUEST_CONTACTS_STATE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
}
All Done! Let’s see how this works
User denies the permission | Rational dialog on next open |
---|---|
The user now sees a rationale dialog since the permission was previously denied and shouldShowRequestPermissionRationale for the given permission has now become true.
Once the user taps on the positive button, the app will request permissions again. Hopefully this time you have convinced your user on why the permission is required.
Here is a Github link for the above project as a sample for your reference.
Cheers! We have successfully implemented rationale dialogs for permissions by following best practices.