Permission Handler in Android: come funziona, gestione delle richieste e implementazione

Autore: IT Sectr Pubblicato: 2026-05-20 Tempo di lettura: 8 min

Permission Handler è un componente delle applicazioni Android responsabile della verifica, richiesta e elaborazione dei risultati delle autorizzazioni runtime. Secondo la Android Developer Guide, 2024, un gestore di autorizzazioni centralizza la logica di checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale in una singola classe o ViewModel. Questo semplifica la manutenzione del codice e migliora i test.

Punti chiave

  • Permission Handler — un componente specializzato per la gestione centralizzata delle autorizzazioni runtime Android.
  • Incapsula la logica di checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale.
  • Le implementazioni moderne si basano su ActivityResultContracts di androidx.activity.
  • Semplifica i test unitari grazie all'inversione delle dipendenze e all'isolamento del codice piattaforma.
  • Le migliori pratiche includono un singolo handler per Activity e il riutilizzo tramite un contenitore DI.

Cos'è Permission Handler in Android

Permission Handler è un pattern architetturale per la gestione centralizzata delle autorizzazioni runtime Android. Invece di chiamate sparse di ContextCompat.checkSelfPermission e ActivityCompat.requestPermissions in tutto il codice dell'applicazione, tutta la logica di richiesta e elaborazione dei risultati è concentrata in una singola classe. Questo riduce la duplicazione, semplifica la manutenzione e rende il codice più prevedibile.

La necessità di Permission Handler è nata con l'introduzione delle autorizzazioni runtime in Android 6.0. Prima di ciò, tutte le autorizzazioni venivano richieste durante l'installazione e il codice dell'applicazione poteva utilizzare qualsiasi API senza verifiche. Dopo il passaggio al modello runtime, ogni utilizzo di un'autorizzazione pericolosa richiede una verifica in tre fasi: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Distribuire questa logica tra Activity e Fragment porta a duplicazione inline ed errori. Secondo Google I/O 2019, centralizzare la gestione delle autorizzazioni riduce il numero di bug relativi a Permission Denial in media del 60 percento.

Un buon Permission Handler fornisce un'interfaccia pulita per il codice chiamante. L'Activity o il Fragment non devono conoscere i dettagli della richiesta — chiamano un metodo come requestCamera(callback), e l'handler stesso gestisce la verifica dello stato, la visualizzazione della motivazione, l'invocazione del dialogo di sistema e il passaggio del risultato al callback. Questo implementa il principio di responsabilità singola e separa la logica di business dal codice delle autorizzazioni della piattaforma.

Quando è necessario un Permission Handler

Un Permission Handler diventa necessario quando un'applicazione utilizza 3 o più autorizzazioni pericolose. Per applicazioni semplici con una sola autorizzazione (ad esempio, fotocamera per uno scanner di codici QR), una chiamata diretta può essere sufficiente. Ma per una tipica applicazione mobile con fotocamera, geolocalizzazione, notifiche e archiviazione — un handler centralizzato è essenziale per la manutenibilità.

Architettura di Permission Handler

Un Permission Handler tipico è composto da tre livelli: un contratto di interfaccia, un'implementazione con ActivityResultLauncher e un livello ViewModel. L'interfaccia definisce i metodi di richiesta per ciascuna autorizzazione — requestCamera, requestLocation, requestStorage. L'implementazione lega questi metodi ai corrispondenti contratti ActivityResultContracts.RequestPermission.

Componenti chiave dell'architettura:

  • PermissionHandlerContract — un'interfaccia con metodi per ciascuna autorizzazione
  • PermissionHandlerImpl — un'implementazione che si connette ad ActivityResultRegistry
  • PermissionResult — una classe sealed con stati GRANTED, DENIED, NEVER_ASK_AGAIN
  • RationaleHandler — un componente per visualizzare spiegazioni prima della richiesta

Questa architettura consente di scambiare facilmente le implementazioni nei test: invece di un ActivityResultLauncher reale, si utilizza un mock che restituisce un risultato predefinito senza interazione con il sistema. Questo è fondamentale per i test unitari della logica dell'interfaccia utente, dove avviare un'Activity per un dialogo di autorizzazione è impossibile.

Gestione del ciclo di vita

Il Permission Handler deve tenere conto del ciclo di vita di Activity e Fragment. I launcher vengono registrati nell'ActivityResultRegistry, che salva e ripristina automaticamente lo stato durante la rotazione dello schermo e la ricreazione dell'Activity. L'handler non deve memorizzare riferimenti diretti ad Activity o Fragment — invece, utilizzare WeakReference o passare il registry attraverso il costruttore. Questo previene perdite di memoria e crash durante i cambi di configurazione.

Implementazione di Permission Handler in Kotlin

Un'implementazione di base di Permission Handler è costruita su ActivityResultContracts.RequestPermission. L'handler riceve l'ActivityResultRegistry da ComponentActivity o Fragment e registra i launcher per ciascuna autorizzazione. Ogni launcher accetta un callback lambda che viene invocato dopo la risposta dell'utente.

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
    }
}

Inizializzazione nell'Activity

L'handler viene inizializzato nell'onCreate dell'Activity tramite registerForActivityResult, che fornisce l'accesso all'ActivityResultRegistry. Dopo l'inizializzazione, l'handler è pronto per elaborare le richieste durante l'intero ciclo di vita dell'Activity. È importante chiamare initialize prima della prima richiesta, altrimenti il launcher non verrà registrato.

Permission Handler con ViewModel

Integrare un Permission Handler con ViewModel è l'approccio più avanzato. Il ViewModel gestisce lo stato delle richieste, mentre l'Handler esegue solo chiamate di piattaforma. Il ViewModel contiene StateFlow<PermissionUiState>, dove UiState descrive quale autorizzazione viene richiesta e quale risultato è stato ricevuto. L'Activity si sottoscrive a questo StateFlow e delega la richiesta all'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()
}

In questo modello, l'Activity verifica isPermissionGranted tramite l'Handler all'avvio, mentre il ViewModel gestisce solo lo stato. Se l'autorizzazione non è concessa — l'Activity si sottoscrive a uiState, chiama requestCamera dall'Handler e passa il risultato al ViewModel tramite onPermissionResult. Separare il codice piattaforma dalla logica di business consente di testare il ViewModel senza dipendenze Android.

Test di Permission Handler

I test unitari di Permission Handler sono possibili grazie all'interfaccia PermissionHandler. Nei test, viene creato un FakePermissionHandler che simula vari scenari: autorizzazione concessa, negata, Never Ask Again. Ogni scenario viene testato indipendentemente. Questo è particolarmente importante per testare la logica dell'interfaccia utente che deve reagire correttamente a tutti e tre i risultati.

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
    }
}

L'implementazione fake consente di testare il ViewModel senza un emulatore. Basta impostare cameraResult al valore desiderato e verificare che il ViewModel aggiorni correttamente il suo UiState. I test di integrazione verificano il PermissionHandler reale con ActivityScenario, ma di solito ci sono solo 2-3 di questi test per applicazione — gli scenari rimanenti sono coperti da test unitari con fake.

Pattern comuni ed errori

Gli errori tipici quando si lavora con Permission Handler includono: non verificare checkSelfPermission prima di ogni chiamata API, ignorare shouldShowRequestPermissionRationale, richiamare requestPermissions dopo Never Ask Again e memorizzare i launcher senza considerare il ciclo di vita dell'Activity. Esaminiamo ogni problema e la sua soluzione.

L'errore più comune è chiamare un'API senza verificare lo stato dell'autorizzazione. Gli sviluppatori presumono che se un'autorizzazione è stata concessa una volta, rimarrà per sempre. Tuttavia, l'utente può revocarla tramite le impostazioni in qualsiasi momento. Un Permission Handler deve sempre chiamare isPermissionGranted prima di eseguire un'operazione sensibile. Il secondo errore comune è ignorare shouldShowRequestPermissionRationale e ripetere la richiesta, che porta a un rifiuto immediato senza dialogo in modalità Never Ask Again.

Le migliori pratiche includono: creare una singola istanza di Handler per l'intero ciclo di vita dell'Activity, utilizzare SharedFlow per passare i risultati al ViewModel, registrare tutte le richieste e i rifiuti per analisi e mostrare un dialogo di motivazione personalizzato prima di quello di sistema al primo rifiuto. Seguire queste regole garantisce una gestione stabile delle autorizzazioni su tutte le versioni di Android.

Domande frequenti

Cos'è Permission Handler in Android?

Permission Handler è un componente per la gestione centralizzata delle autorizzazioni runtime, che incapsula checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale. Semplifica la manutenzione del codice e migliora i test.

Quale API utilizzare per Handler nel 2024?

Si consiglia di utilizzare ActivityResultContracts.RequestPermission dalla libreria androidx.activity. Sostituisce il deprecato onRequestPermissionsResult e fornisce un'API callback pulita con un risultato Boolean.

È necessario un Handler per una singola autorizzazione?

Per una singola autorizzazione, un Handler non è obbligatorio — è possibile utilizzare una chiamata diretta al launcher RequestPermission nell'Activity. Un Handler diventa necessario con 3 o più autorizzazioni per evitare la duplicazione del codice.

Come testare un Permission Handler?

Creare un'interfaccia PermissionHandler e la sua implementazione fake per i test unitari. Il fake restituisce risultati predefiniti senza chiamate di sistema. Questo consente di testare ViewModel e logica dell'interfaccia utente senza emulatore.

Come gestire Never Ask Again in un Handler?

Dopo il rifiuto, verificare shouldShowRequestPermissionRationale. Se il metodo restituisce false — la modalità Never Ask Again è attiva. L'Handler deve restituire PermissionResult.DENIED(false) e l'interfaccia utente deve mostrare un pulsante per andare alle Impostazioni.

Riepilogo

  • Permission Handler è un componente architetturale per la gestione centralizzata delle autorizzazioni runtime Android.
  • Basato su ActivityResultContracts.RequestPermission dalla libreria androidx.activity.
  • Un'interfaccia con metodi per ciascuna autorizzazione semplifica i test unitari tramite implementazioni fake.
  • L'integrazione con ViewModel tramite StateFlow separa il codice piattaforma dalla logica di business.
  • Errori tipici: mancanza di checkSelfPermission, ignorare la motivazione e Never Ask Again.
  • Migliore pratica — un Handler per Activity registrato in onCreate.
  • La centralizzazione riduce il numero di bug Permission Denial del 60 percento nei progetti tipici.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche