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.
Runtime Permissions Android (Demo App)
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
Get Solution Code
Read our android architecture components tutorials series