Cómo agregar permisos de tiempo de ejecución a tu app en Kotlin

1. Bienvenida

Introducción

Los permisos de la app se usan para brindar acceso a los datos y las funcionalidades que proporciona la zona de pruebas de la app. Para mejorar la funcionalidad de tu app, debes permitir el acceso a Internet, a la ubicación del dispositivo, a la cámara, y mucho más.

A fin de usar estas capacidades, deberás solicitarle permisos al usuario. En este codelab, te guiaremos por los pasos necesarios para agregar permisos de tiempo de ejecución y verificar si se otorgaron o no.

Requisitos

Conocimientos que ya deberías tener

Qué aprenderás

  • Cómo agregar permisos al manifiesto de Android
  • Cómo solicitar permisos
  • Cómo controlar cuándo se aceptan y se rechazan permisos
  • Cómo verificar si se otorgó un permiso

Qué compilarás

Crearás una app que solicite un permiso para acceder a la cámara. Implementarás la parte del permiso de la app, pero no la parte de la cámara.

2. Cómo crear un proyecto de Android Studio

  1. Inicia un proyecto nuevo de Android Studio.
  2. Selecciona Empty Activity.

70e5de28256e3dcb.png

  1. Asígnale el nombre Permissions Codelab al proyecto y establece el lenguaje en Kotlin.

f2948b584ca99c47.png

3. Cómo configurar el código

  1. Agrega las últimas versiones de las siguientes dependencias al archivo build.gradle del nivel de app. Estas versiones te permiten usar la biblioteca Activity que se tratará más adelante en el codelab.
implementation "androidx.activity:activity-ktx:1.2.2"
implementation "androidx.fragment:fragment-ktx:1.3.2"
  1. Establece la opción de compilación viewBinding como verdadera en el bloque de Android para habilitar ViewBinding.
android {
   ...
   buildFeatures {
       viewBinding true
   }
}
  1. Luego, presiona el botón de martillo verde para compilar. Esto generará una clase de vinculación llamada ActivityMainBinding que usarás más adelante para ViewBinding.

d4064454e5c50111.png

  1. Navega al archivo activity_main.xml y reemplaza el código por este.
<?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:id="@+id/main_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Request Permissions"
       android:onClick="onClickRequestPermission"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Agrega estas strings al archivo strings.xml.
<string name="app_name">Permissions Codelab</string>
<string name="permission_required">Camera access is required to display the camera preview.</string>
<string name="ok">OK</string>
<string name="permission_granted">Permission is granted. You can use the camera now.</string>
  1. En MainActivity.kt, arriba del método onCreate(), define las variables para el diseño y el elemento ViewBinding.
private lateinit var layout: View
private lateinit var binding: ActivityMainBinding
  1. Reemplaza el código del método onCreate() con el siguiente código. Este código inicializa la vinculación, crea un elemento val para representar la vista y lo establece en la raíz de la vinculación, y establece el diseño en el elemento mainLayout de la vinculación.
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   binding = ActivityMainBinding.inflate(layoutInflater)
   val view = binding.root
   layout = binding.mainLayout
   setContentView(view)
}
  1. En la parte inferior del archivo, debajo de la clase MainActivity, agrega una función de extensión para mostrar las barras de notificaciones en todo el codelab.
fun View.showSnackbar(
   view: View,
   msg: String,
   length: Int,
   actionMessage: CharSequence?,
   action: (View) -> Unit
) {
   val snackbar = Snackbar.make(view, msg, length)
   if (actionMessage != null) {
       snackbar.setAction(actionMessage) {
           action(this)
       }.show()
   } else {
       snackbar.show()
   }
}

4. Cómo agregar un permiso al manifiesto

Lo primero que debes hacer es declarar que se usará tu permiso en Android manifest con la etiqueta <uses-permission>.

Con frecuencia, el permiso que solicitas también tendrá otros requisitos. En este caso, no puedes usar una app de cámara, a menos que el dispositivo tenga una cámara. Por este motivo, también agregarás la etiqueta <uses-feature> al manifiesto.

  1. En el archivo AndroidManifest.xml, agrega el permiso para acceder a la cámara arriba de la etiqueta <application>.
<uses-permission android:name="android.permission.CAMERA" />

5. Cómo crear un selector de permisos

En MainActivity.kt, crea un val con el nombre requestPermissionLaunchery copia el código en este. En las siguientes viñetas, se explicará lo que incluye este código.

private val requestPermissionLauncher =
   registerForActivityResult(
       ActivityResultContracts.RequestPermission()
   ) { isGranted: Boolean ->
       if (isGranted) {
           Log.i("Permission: ", "Granted")
       } else {
           Log.i("Permission: ", "Denied")
       }
   }
private val requestPermissionLauncher =
   registerForActivityResult(
       ActivityResultContracts.RequestPermission())
  • Agrega una devolución de llamada para controlar el caso en el que se otorga o no. En este caso, registramos el resultado.
{ isGranted: Boolean ->
       if (isGranted) {
           Log.i("Permission: ", "Granted")
       } else {
           Log.i("Permission: ", "Denied")
       }
}

6. Cómo solicitar un permiso

  1. Crea una función con el nombre onClickRequestPermission(view: View) y copia el código en esta. En las siguientes viñetas, explicaremos lo que sucede dentro del código.
fun onClickRequestPermission(view: View) {
   when {
       ContextCompat.checkSelfPermission(
           this,
           Manifest.permission.CAMERA
       ) == PackageManager.PERMISSION_GRANTED -> {
           layout.showSnackbar(
               view,
               getString(R.string.permission_granted),
               Snackbar.LENGTH_INDEFINITE,
               null
           ) {}
       }

       ActivityCompat.shouldShowRequestPermissionRationale(
           this,
           Manifest.permission.CAMERA
       ) -> {
           layout.showSnackbar(
               view,
               getString(R.string.permission_required),
               Snackbar.LENGTH_INDEFINITE,
               getString(R.string.ok)
           ) {
               requestPermissionLauncher.launch(
                   Manifest.permission.CAMERA
               )
           }
       }

       else -> {
           requestPermissionLauncher.launch(
               Manifest.permission.CAMERA
           )
       }
   }
}
  • Configura una sentencia when para cubrir tres casos: si ya se otorgó el permiso, si la app considera que debería mostrar la lógica del permiso de solicitud y si todavía no se solicitó.
when {
   ContextCompat.checkSelfPermission(
       this,
       Manifest.permission.CAMERA
   ) == PackageManager.PERMISSION_GRANTED -> {

   }

   ActivityCompat.shouldShowRequestPermissionRationale(
       this,
       Manifest.permission.CAMERA
   ) -> {

   }

   else -> {

   }
}
  • En el caso en que se haya otorgado el permiso, muestra una barra de notificaciones que lo anuncie.
ContextCompat.checkSelfPermission(
   this,
   Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
   layout.showSnackbar(
       view,
       getString(R.string.permission_granted),
       Snackbar.LENGTH_INDEFINITE,
       null
   ) {}
}
  • Si shouldShowRequestPermissionRationale() muestra un valor verdadero, se ofrece una IU que describa, con más detalles, el motivo por el que la función necesita ese permiso particular y que también le brinde al usuario una manera de aceptar o rechazar el permiso de la IU.

a25d8c6c1d5051d.png

ActivityCompat.shouldShowRequestPermissionRationale(
   this,
   Manifest.permission.CAMERA
) -> {
   layout.showSnackbar(
       view,
       getString(R.string.permission_required),
       Snackbar.LENGTH_INDEFINITE,
       getString(R.string.ok)
   ) {
       requestPermissionLauncher.launch(
           Manifest.permission.CAMERA
       )
   }
}
  • De lo contrario, solicita el permiso.
else -> {
   requestPermissionLauncher.launch(
       Manifest.permission.CAMERA
   )
}

7. Resumen

¡Eso es todo! En este codelab, te mostramos la manera de agregar permisos de tiempo de ejecución, y se puede usar para permisos relacionados con la ubicación, la red, el contenido multimedia y mucho más.

Puedes consultar el código final y leer más en la documentación.