Permission Handler en Android: cómo funciona, manejo de solicitudes e implementación

Autor: IT Sectr Publicado: 2026-05-20 Tiempo de lectura: 8 min

Permission Handler es un componente de aplicaciones Android responsable de verificar, solicitar y procesar los resultados de permisos en tiempo de ejecución. Según la Android Developer Guide, 2024, un controlador de permisos centraliza la lógica de checkSelfPermission, requestPermissions y shouldShowRequestPermissionRationale en una sola clase o ViewModel. Esto simplifica el mantenimiento del código y mejora las pruebas.

Puntos clave

  • Permission Handler — un componente especializado para la gestión centralizada de permisos en tiempo de ejecución de Android.
  • Encapsula la lógica de checkSelfPermission, requestPermissions y shouldShowRequestPermissionRationale.
  • Las implementaciones modernas se basan en ActivityResultContracts de androidx.activity.
  • Simplifica las pruebas unitarias gracias a la inversión de dependencias y el aislamiento del código de plataforma.
  • Las mejores prácticas incluyen un único handler por Activity y la reutilización a través de un contenedor DI.

¿Qué es Permission Handler en Android?

Permission Handler es un patrón arquitectónico para la gestión centralizada de permisos en tiempo de ejecución de Android. En lugar de llamadas dispersas a ContextCompat.checkSelfPermission y ActivityCompat.requestPermissions por todo el código de la aplicación, toda la lógica de solicitudes y procesamiento de resultados se concentra en una sola clase. Esto reduce la duplicación, simplifica el mantenimiento y hace que el código sea más predecible.

La necesidad de Permission Handler surgió con la introducción de permisos en tiempo de ejecución en Android 6.0. Antes de eso, todos los permisos se solicitaban al instalar la aplicación, y el código podía usar cualquier API sin verificaciones. Después de migrar al modelo de ejecución, cada uso de un permiso peligroso requiere una verificación de tres pasos: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Distribuir esta lógica entre Activity y Fragment genera duplicación en línea y errores. Según Google I/O 2019, centralizar el manejo de permisos reduce la cantidad de errores relacionados con Permission Denial en un promedio del 60 por ciento.

Un buen Permission Handler proporciona una interfaz limpia para el código que lo invoca. La Activity o Fragment no deben conocer los detalles de la solicitud — llaman a un método como requestCamera(callback), y el propio handler gestiona la verificación del estado, la visualización de la justificación, la invocación del diálogo del sistema y la transmisión del resultado al callback. Esto implementa el principio de responsabilidad única y separa la lógica de negocio del código de permisos de la plataforma.

¿Cuándo se necesita un Permission Handler?

Un Permission Handler se vuelve necesario cuando una aplicación utiliza 3 o más permisos peligrosos. Para aplicaciones simples con un solo permiso (por ejemplo, cámara para un escáner de códigos QR), una llamada directa puede ser suficiente. Pero para una aplicación móvil típica con cámara, geolocalización, notificaciones y almacenamiento — un handler centralizado es esencial para el mantenimiento.

Arquitectura de Permission Handler

Un Permission Handler típico consta de tres capas: un contrato de interfaz, una implementación con ActivityResultLauncher y una capa de ViewModel. La interfaz define métodos de solicitud para cada permiso — requestCamera, requestLocation, requestStorage. La implementación vincula estos métodos con los contratos ActivityResultContracts.RequestPermission correspondientes.

Componentes clave de la arquitectura:

  • PermissionHandlerContract — una interfaz con métodos para cada permiso
  • PermissionHandlerImpl — una implementación que se conecta con ActivityResultRegistry
  • PermissionResult — una clase sellada con los estados GRANTED, DENIED, NEVER_ASK_AGAIN
  • RationaleHandler — un componente para mostrar explicaciones antes de la solicitud

Esta arquitectura permite intercambiar fácilmente las implementaciones en las pruebas: en lugar de un ActivityResultLauncher real, se utiliza un mock que devuelve un resultado predefinido sin interacción con el sistema. Esto es fundamental para las pruebas unitarias de la lógica de UI, donde iniciar una Activity para un diálogo de permisos es imposible.

Gestión del ciclo de vida

El Permission Handler debe tener en cuenta el ciclo de vida de Activity y Fragment. Los launchers se registran en el ActivityResultRegistry, que guarda y restaura automáticamente el estado al rotar la pantalla o al recrear la Activity. El handler no debe almacenar referencias directas a Activity o Fragment — en su lugar, use WeakReference o pase el registry a través del constructor. Esto evita pérdidas de memoria y fallos durante los cambios de configuración.

Implementación de Permission Handler en Kotlin

Una implementación básica de Permission Handler se construye sobre ActivityResultContracts.RequestPermission. El handler recibe el ActivityResultRegistry de ComponentActivity o Fragment y registra launchers para cada permiso. Cada launcher acepta una lambda de callback que se invoca después de que el usuario responda.

kotlin
sealed class PermissionResult {
    object GRANTED : PermissionResult()
    data class DENIED(
        val shouldShowRationale: Boolean
    ) : PermissionResult()
}

interface PermissionHandler {
    fun requestCamera(
        callback: (PermissionResult) -> Unit
    )
    fun requestLocation(
        callback: (PermissionResult) -> Unit
    )
    fun isPermissionGranted(
        permission: String
    ): Boolean
}

class AndroidPermissionHandler(
    private val registry: ActivityResultRegistry,
    private val context: Context
) : PermissionHandler {

    private var cameraLauncher: ActivityResultLauncher<String>? = null

    fun initialize() {
        cameraLauncher = registry.register(
            "camera_permission",
            ActivityResultContracts.RequestPermission()
        ) { isGranted ->
            if (isGranted) {
                pendingCameraCallback?.invoke(
                    PermissionResult.GRANTED
                )
            } else {
                val rationale = ActivityCompat.shouldShowRequestPermissionRationale(
                    context as Activity,
                    Manifest.permission.CAMERA
                )
                pendingCameraCallback?.invoke(
                    PermissionResult.DENIED(rationale)
                )
            }
        }
    }

    private var pendingCameraCallback:
        ((PermissionResult) -> Unit)? = null

    override fun requestCamera(
        callback: (PermissionResult) -> Unit
    ) {
        if (isPermissionGranted(
                Manifest.permission.CAMERA
        )) {
            callback.invoke(PermissionResult.GRANTED)
            return
        }
        pendingCameraCallback = callback
        cameraLauncher?.launch(
            Manifest.permission.CAMERA
        )
    }

    override fun isPermissionGranted(
        permission: String
    ): Boolean {
        return ContextCompat.checkSelfPermission(
            context, permission
        ) == PackageManager.PERMISSION_GRANTED
    }
}

Inicialización en Activity

El handler se inicializa en el onCreate de la Activity a través de registerForActivityResult, que proporciona acceso al ActivityResultRegistry. Después de la inicialización, el handler está listo para procesar solicitudes durante todo el ciclo de vida de la Activity. Es importante llamar a initialize antes de la primera solicitud, de lo contrario el launcher no se registrará.

Permission Handler con ViewModel

Integrar un Permission Handler con ViewModel es el enfoque más avanzado. El ViewModel gestiona el estado de las solicitudes, mientras que el Handler solo realiza llamadas de plataforma. El ViewModel contiene StateFlow<PermissionUiState>, donde UiState describe qué permiso se está solicitando y qué resultado se recibió. La Activity se suscribe a este StateFlow y delega la solicitud al Handler.

kotlin
class PermissionsViewModel : ViewModel() {

    private val _uiState =
        MutableStateFlow<PermissionUiState>(
            PermissionUiState.Idle
        )
    val uiState: StateFlow<PermissionUiState> = _uiState.asStateFlow()

    fun onCameraRequested() {
        _uiState.value = PermissionUiState.RequestingCamera
    }

    fun onPermissionResult(
        permission: String,
        result: PermissionResult
    ) {
        when (result) {
            PermissionResult.GRANTED -> {
                _uiState.value = PermissionUiState.Granted(permission)
            }
            is PermissionResult.DENIED -> {
                _uiState.value = PermissionUiState.Denied(
                    permission,
                    result.shouldShowRationale
                )
            }
        }
    }
}

sealed class PermissionUiState {
    object Idle : PermissionUiState()
    object RequestingCamera : PermissionUiState()
    data class Granted(val permission: String) : PermissionUiState()
    data class Denied(
        val permission: String,
        val shouldShowRationale: Boolean
    ) : PermissionUiState()
}

En este modelo, la Activity verifica isPermissionGranted a través del Handler al inicio, mientras que el ViewModel solo gestiona el estado. Si el permiso no está concedido — la Activity se suscribe a uiState, llama a requestCamera del Handler y pasa el resultado de vuelta al ViewModel a través de onPermissionResult. Separar el código de plataforma de la lógica de negocio permite probar el ViewModel sin dependencias de Android.

Pruebas de Permission Handler

Las pruebas unitarias de Permission Handler son posibles gracias a la interfaz PermissionHandler. En las pruebas, se crea un FakePermissionHandler que simula varios escenarios: permiso concedido, denegado, Never Ask Again. Cada escenario se prueba de forma independiente. Esto es especialmente importante para probar la lógica de UI que debe reaccionar correctamente a los tres resultados.

kotlin
class FakePermissionHandler : PermissionHandler {

    var cameraResult: PermissionResult =
        PermissionResult.GRANTED
    var grantedPermissions: Set<String> =
        setOf(Manifest.permission.CAMERA)

    override fun requestCamera(
        callback: (PermissionResult) -> Unit
    ) {
        callback.invoke(cameraResult)
    }

    override fun isPermissionGranted(
        permission: String
    ): Boolean {
        return permission in grantedPermissions
    }
}

La implementación fake permite probar ViewModel sin un emulador. Simplemente establezca cameraResult en el valor deseado y verifique que el ViewModel actualice correctamente su UiState. Las pruebas de integración verifican el PermissionHandler real con ActivityScenario, pero normalmente solo hay 2-3 de estas pruebas por aplicación — los escenarios restantes se cubren con pruebas unitarias usando fakes.

Patrones comunes y errores

Los errores típicos al trabajar con Permission Handler incluyen: no verificar checkSelfPermission antes de cada llamada a la API, ignorar shouldShowRequestPermissionRationale, volver a llamar a requestPermissions después de Never Ask Again y almacenar launchers sin considerar el ciclo de vida de la Activity. Examinemos cada problema y su solución.

El error más común es llamar a una API sin verificar el estado del permiso. Los desarrolladores asumen que si un permiso se concedió una vez, permanecerá para siempre. Sin embargo, el usuario puede revocarlo a través de la configuración en cualquier momento. Un Permission Handler siempre debe llamar a isPermissionGranted antes de realizar una operación sensible. El segundo error popular es ignorar shouldShowRequestPermissionRationale y repetir la solicitud, lo que lleva a una denegación instantánea sin diálogo en modo Never Ask Again.

Las mejores prácticas incluyen: crear una única instancia de Handler para todo el ciclo de vida de la Activity, usar SharedFlow para pasar resultados al ViewModel, registrar todas las solicitudes y denegaciones para análisis, y mostrar un diálogo de justificación personalizado antes del del sistema en la primera denegación. Seguir estas reglas garantiza un manejo estable de permisos en todas las versiones de Android.

Preguntas frecuentes

¿Qué es Permission Handler en Android?

Permission Handler es un componente para la gestión centralizada de permisos en tiempo de ejecución, que encapsula checkSelfPermission, requestPermissions y shouldShowRequestPermissionRationale. Simplifica el mantenimiento del código y mejora las pruebas.

¿Qué API usar para Handler en 2024?

Se recomienda usar ActivityResultContracts.RequestPermission de la biblioteca androidx.activity. Reemplaza el obsoleto onRequestPermissionsResult y proporciona una API de callback limpia con un resultado Boolean.

¿Se necesita un Handler para un solo permiso?

Para un solo permiso, un Handler no es obligatorio — puede usar una llamada directa al launcher RequestPermission en la Activity. Un Handler se vuelve necesario con 3 o más permisos para evitar la duplicación de código.

¿Cómo probar un Permission Handler?

Cree una interfaz PermissionHandler y su implementación fake para pruebas unitarias. El fake devuelve resultados predefinidos sin llamadas al sistema. Esto permite probar la ViewModel y la lógica de UI sin emulador.

¿Cómo manejar Never Ask Again en un Handler?

Después de la denegación, verifique shouldShowRequestPermissionRationale. Si el método devuelve false — el modo Never Ask Again está activo. El Handler debe devolver PermissionResult.DENIED(false), y la UI debe mostrar un botón para ir a Configuración.

Resumen

  • Permission Handler es un componente arquitectónico para la gestión centralizada de permisos en tiempo de ejecución de Android.
  • Se basa en ActivityResultContracts.RequestPermission de la biblioteca androidx.activity.
  • Una interfaz con métodos para cada permiso simplifica las pruebas unitarias a través de implementaciones fake.
  • La integración con ViewModel mediante StateFlow separa el código de plataforma de la lógica de negocio.
  • Errores típicos: falta de checkSelfPermission, ignorar rationale y Never Ask Again.
  • Mejor práctica — un Handler por Activity registrado en onCreate.
  • La centralización reduce la cantidad de errores Permission Denial en un 60 por ciento en proyectos típicos.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también