Core Android

Best Practices of Runtime Permissions Android

Welcome to android marshmallow runtime permissions example. In this article, I’ll tell you to best practices of runtime permissions in android. For doing that will create a sample app and learn best practices of handle runtime permissions using a robust, reusable and minimum line of code. So let’s started

Runtime permissions

Android 6.0 introduced a new runtime permission model. Based on the protection level we can divide into two categories normal and dangerous.

As you know every android app has a limited access android system( normal permission). If an app needs to use these resources(dangerous permission), the app has to request particular permission. For doing that you have to declare needed permission in the app manifest. Then the app has to request the user for approval each permission at runtime on an Android Marshmallow (6.0 ) and onward.

1. Create an android project

Let’s move to an android studio, create a new project with kotlin using the default template. In this android example, we’ll use Snackbar for displaying message. I’m adding material io dependency inside the app build.gradle

implementation 'com.google.android.material:material:1.0.0'
2. Write a View extension named ViewExt

Create a new file named is ViewExt and paste below code.

package com.runtimepermissionsexample.util

import android.view.View
import com.google.android.material.snackbar.Snackbar

fun View.showSnackbar(msgId: Int, length: Int) {
    showSnackbar(context.getString(msgId), length)
}

fun View.showSnackbar(msg: String, length: Int) {
    showSnackbar(msg, length, null, {})
}

fun View.showSnackbar(
    msgId: Int,
    length: Int,
    actionMessageId: Int,
    action: (View) -> Unit
) {
    showSnackbar(context.getString(msgId), length, context.getString(actionMessageId), action)
}

fun View.showSnackbar(
    msg: String,
    length: Int,
    actionMessage: CharSequence?,
    action: (View) -> Unit
) {
    val snackbar = Snackbar.make(this, msg, length)
    if (actionMessage != null) {
        snackbar.setAction(actionMessage) {
            action(this)
        }
    }
    snackbar.show()
}
3. Create an extension class for an AppCompatActivity
package com.runtimepermissionsexample.util

import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat

fun AppCompatActivity.checkPermission(permission: String) =
    ActivityCompat.checkSelfPermission(this, permission)

fun AppCompatActivity.shouldRequestPermissionRationale(permission: String) =
    ActivityCompat.shouldShowRequestPermissionRationale(this, permission)

fun AppCompatActivity.requestAllPermissions(
    permissionsArray: Array<String>,
    requestCode: Int
) {
    ActivityCompat.requestPermissions(this, permissionsArray, requestCode)
}
4. Add uses permission in manifest

Now add all uses permission inside the manifest. In this example, I’m taken storage permission

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
5. Open main activity layout file add below code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/buttonDownloadFile"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Download"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
6. Check for permissions
  // Check if the storage permission has been granted
        if (checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            // Permission is already granted
        } else {
            //Requested permission.
        }
7. Request the permissions
 // Permission has not been granted and must be requested.
        if (shouldRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // Provide an additional rationale to the user if the permission was not granted
            container.showSnackbar(
                R.string.storage_access_required,
                Snackbar.LENGTH_INDEFINITE, R.string.ok
            ) {
                requestAllPermissions(permissions, PERMISSION_REQUEST_STORAGE)
            }

        } else {
            // Request the permission with array.
            requestAllPermissions(permissions, PERMISSION_REQUEST_STORAGE)
        }
7. Handle the request permissions
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == PERMISSION_REQUEST_STORAGE) {
            // Request for camera permission.
            if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              
            } else {
                // Permission request was denied.
            }
        }
    }
8. Runtime permissions final activity source code
package com.runtimepermissionsexample

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.runtimepermissionsexample.util.checkPermission
import com.runtimepermissionsexample.util.requestAllPermissions
import com.runtimepermissionsexample.util.shouldRequestPermissionRationale
import com.runtimepermissionsexample.util.showSnackbar
import kotlinx.android.synthetic.main.activity_main.buttonDownloadFile
import kotlinx.android.synthetic.main.activity_main.container

class MainActivity : AppCompatActivity() {

  companion object {
    const val PERMISSION_REQUEST_STORAGE = 0
  }

  private val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    buttonDownloadFile.setOnClickListener { downloadFile() }
  }

  private fun downloadFile() {
    // Check if the storage permission has been granted
    if (checkPermission(
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED
    ) {
      // Permission is already granted
      startDownloading()
    } else {
      //Requested permission.
      requestStoragePermission()
    }
  }

  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
  ) {
    if (requestCode == PERMISSION_REQUEST_STORAGE) {
      // Request for camera permission.
      if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        startDownloading()
      } else {
        // Permission request was denied.
        container.showSnackbar(R.string.storage_permission_denied, Snackbar.LENGTH_SHORT)
      }
    }
  }

  private fun requestStoragePermission() {
    // Permission has not been granted and must be requested.
    if (shouldRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
      // Provide an additional rationale to the user if the permission was not granted
      container.showSnackbar(
          R.string.storage_access_required,
          Snackbar.LENGTH_INDEFINITE, R.string.ok
      ) {
        requestAllPermissions(permissions, PERMISSION_REQUEST_STORAGE)
      }

    } else {
      // Request the permission with array.
      requestAllPermissions(permissions, PERMISSION_REQUEST_STORAGE)
    }
  }

  private fun startDownloading() {
    // do download stuff here
    container.showSnackbar(R.string.downloading, Snackbar.LENGTH_LONG)

  }
}
Conclusion

In this runtime permission android, we learned best practices of requesting runtime permissions android. I hope it’s helpful for you, then help me by sharing this post with all your friends

Read our android architecture components tutorials series

Leave a Reply