Android

Solicitar permisos en Fragment de Android con Kotlin

Hoy estaba trabajando con Android y Kotlin hasta que llegué a la parte de solicitar permisos desde un fragmento o fragment y aparecieron algunos errores.

Entre los errores puedo destacar que los permisos no se solicitaban, no se llamaba a onRequestPermissionsResult, etcétera.

Así que aquí te mostraré cómo solicitar permisos en Android desde un Fragment usando Kotlin. Obviamente será más una explicación de cómo lo hice yo, y no un paso a paso.

El manifiesto

Recuerda que debes indicar los permisos en el manifiesto. Yo solo quiero acceder a la ubicación así que quedó así:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Saber si tiene permisos

Ahora una función que recibe un arreglo de permisos y verifica si todos están concedidos:

private fun tienePermisos(permisos: Array<String>): Boolean {
    return permisos.all {
        return ContextCompat.checkSelfPermission(
            requireActivity(),
            it
        ) == PackageManager.PERMISSION_GRANTED
    }
}

Solicitar permisos

Luego definí una función que solicita un arreglo de permisos. En este caso he definido la variable CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO al inicio de mi fragmento:

private val CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO = 2106

Este código de solicitud es un número propio. Puede tener cualquier valor siempre y cuando no se repita dentro de tu app. Ya verás cómo uso la función más tarde.

private fun solicitarPermisos(permisos: Array<String>) {
    requestPermissions(
        permisos,
        CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO
    )
}

Nota importante: aquí estaba mi error, pues invocaba a ActivityCompat.requestPermissions o ContextCompat.requestPermissions y eso hacía que no se invocara a onRequestPermissionsResult dentro del fragmento (se invocaba en la Activity padre) así que ten cuidado.

Verificar permisos

Aquí viene la función interesante. En este caso la función se encarga de verificar si tiene permisos, y si la app no los tiene, los solicita:

private fun verificarPermisos() {
    val permisos = arrayListOf(
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACCESS_FINE_LOCATION,
    )
    // Segundo plano para Android Q
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        permisos.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
    }
    val permisosComoArray = permisos.toTypedArray()
    if (tienePermisos(permisosComoArray)) {
        haConcedidoPermisos = true
        // Los permisos ya fueron concedidos
    } else {
        solicitarPermisos(permisosComoArray)
    }
}

No le hagas mucho caso a lo de la línea 6, pues eso solo es necesario para este ejemplo específico. Lo importante es definir la lista de permisos que se van a usar en la línea 2, y luego verificar en la línea 11.

En caso de que haya permisos, ya puedes hacer lo que sea que vayas a hacer, pues los permisos ya fueron concedidos anteriormente o desde otro lugar.

Si los permisos no han sido concedidos, entonces se van a solicitar en la línea 15. Recuerda que los resultados van a ser pasados a la función onRequestPermissionsResult.

onRequestPermissionsResult

Y esta función será llamada después de que se le haya solicitado al usuario la lista de permisos. Esto será llamado ya sea que el usuario haya aceptado o no, así que vamos a verificar.

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    if (requestCode == CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO) {
        val todosLosPermisosConcedidos =
            grantResults.all { it == PackageManager.PERMISSION_GRANTED }
        if (grantResults.isNotEmpty() && todosLosPermisosConcedidos) {
            haConcedidoPermisos = true;
            //El usuario concedió todos los permisos
        } else {
            // Uno o más permisos fueron denegados
        }
    }
}

Fíjate en que estoy verificando el código de solicitud para saber si esa respuesta es por la petición que hice.

Ahora verifico que todos los permisos hayan sido concedidos y en caso de que sí establezco la bandera en true.

En caso de que no, puedes hacer lo que creas conveniente (yo no dejaría a los usuarios usar mi app hasta que concedan los permisos, pero no soy experto en UX así que no me hagas caso)

A partir de aquí puedes estar seguro de que el usuario dio permisos, aunque recuerda que siempre debes verificar si cuentas con los permisos antes de hacer algo, usando la función tienePermisos.

Código completo

Si te sirve de algo, te dejo el código completo de mi Fragment

package me.parzibyte.algunproyecto

import android.Manifest
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import android.content.pm.PackageManager
import android.os.Build
import android.util.Log

import androidx.core.content.ContextCompat


class EnviarUbicacionService : Fragment() {

    private val CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO = 2106
    private val LOG_TAG = "EnviarUbicacion"
    private var haConcedidoPermisos = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        verificarPermisos()
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_enviar_ubicacion_service, container, false)
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO) {
            val todosLosPermisosConcedidos =
                grantResults.all { it == PackageManager.PERMISSION_GRANTED }
            if (grantResults.isNotEmpty() && todosLosPermisosConcedidos) {
                haConcedidoPermisos = true;
                Log.d(LOG_TAG, "El usuario concedió todos los permisos")
            } else {
                Log.d(LOG_TAG, "Uno o más permisos fueron denegados")
            }
        }
    }

    private fun verificarPermisos() {
        val permisos = arrayListOf(
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
        )
        // Segundo plano para Android Q
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            permisos.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        }
        val permisosComoArray = permisos.toTypedArray()
        if (tienePermisos(permisosComoArray)) {
            haConcedidoPermisos = true
            Log.d(LOG_TAG, "Los permisos ya fueron concedidos")
        } else {
            solicitarPermisos(permisosComoArray)
        }
    }


    private fun solicitarPermisos(permisos: Array<String>) {
        Log.d(LOG_TAG, "Solicitando permisos...")
        requestPermissions(
            permisos,
            CODIGO_PERMISOS_UBICACION_SEGUNDO_PLANO
        )
    }

    private fun tienePermisos(permisos: Array<String>): Boolean {
        return permisos.all {
            return ContextCompat.checkSelfPermission(
                requireActivity(),
                it
            ) == PackageManager.PERMISSION_GRANTED
        }
    }

}

Nota: si tú usas Java y Activity ya hice un tutorial de cómo solicitar permisos en Android.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Hola, en la documentación de android se menciona que a partir de android 11 para obtener los permisos en segundo plano es necesario hacer que el usuario se dirija a los ajustes de la aplicación, en especifico la parte en donde se coloca que se da acceso a la ubicación en segundo plano, como se hace esa parte?, o esta cubierta en este ejemplo?

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

4 días hace

Esta web usa cookies.