Permission Handler no Android: como funciona, tratamento de solicitações e implementação

Autor: IT Sectr Publicado: 2026-05-20 Tempo de leitura: 8 min

Permission Handler é um componente de aplicativos Android responsável por verificar, solicitar e processar os resultados de permissões em tempo de execução. De acordo com o Android Developer Guide, 2024, um handler de permissões centraliza a lógica de checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale em uma única classe ou ViewModel. Isso simplifica a manutenção do código e melhora os testes.

Principais pontos

  • Permission Handler — um componente especializado para gerenciamento centralizado de permissões em tempo de execução do Android.
  • Encapsula a lógica de checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale.
  • Implementações modernas são baseadas em ActivityResultContracts da androidx.activity.
  • Simplifica os testes unitários graças à inversão de dependências e ao isolamento do código de plataforma.
  • As melhores práticas incluem um único handler por Activity e reutilização por meio de um contêiner DI.

O que é Permission Handler no Android

Permission Handler é um padrão arquitetural para gerenciamento centralizado de permissões em tempo de execução do Android. Em vez de chamadas dispersas de ContextCompat.checkSelfPermission e ActivityCompat.requestPermissions por todo o código do aplicativo, toda a lógica de solicitações e processamento de resultados é concentrada em uma única classe. Isso reduz duplicação, simplifica a manutenção e torna o código mais previsível.

A necessidade de um Permission Handler surgiu com a introdução de permissões em tempo de execução no Android 6.0. Antes disso, todas as permissões eram solicitadas no momento da instalação, e o código do aplicativo podia usar qualquer API sem verificações. Após a migração para o modelo de execução, cada uso de uma permissão perigosa requer uma verificação em três etapas: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Espalhar essa lógica entre Activity e Fragment gera duplicação inline e erros. De acordo com o Google I/O 2019, centralizar o tratamento de permissões reduz o número de bugs relacionados a Permission Denial em uma média de 60 por cento.

Um bom Permission Handler fornece uma interface limpa para o código chamador. A Activity ou Fragment não precisa saber os detalhes da solicitação — eles chamam um método como requestCamera(callback), e o próprio handler gerencia a verificação de status, exibição de justificativa, invocação do diálogo do sistema e passagem do resultado para o callback. Isso implementa o princípio de responsabilidade única e separa a lógica de negócios do código de permissões da plataforma.

Quando é necessário um Permission Handler

Um Permission Handler torna-se necessário quando um aplicativo usa 3 ou mais permissões perigosas. Para aplicativos simples com uma permissão (por exemplo, câmera para um scanner de QR code), uma chamada direta pode ser suficiente. Mas para um aplicativo móvel típico com câmera, geolocalização, notificações e armazenamento — um handler centralizado é essencial para a manutenção.

Arquitetura do Permission Handler

Um Permission Handler típico consiste em três camadas: um contrato de interface, uma implementação com ActivityResultLauncher e uma camada de ViewModel. A interface define métodos de solicitação para cada permissão — requestCamera, requestLocation, requestStorage. A implementação vincula esses métodos aos contratos ActivityResultContracts.RequestPermission correspondentes.

Componentes-chave da arquitetura:

  • PermissionHandlerContract — uma interface com métodos para cada permissão
  • PermissionHandlerImpl — uma implementação que se conecta ao ActivityResultRegistry
  • PermissionResult — uma classe selada com estados GRANTED, DENIED, NEVER_ASK_AGAIN
  • RationaleHandler — um componente para exibir explicações antes da solicitação

Essa arquitetura permite trocar facilmente as implementações nos testes: em vez de um ActivityResultLauncher real, usa-se um mock que retorna um resultado predefinido sem interação com o sistema. Isso é fundamental para testes unitários da lógica de UI, onde iniciar uma Activity para um diálogo de permissão é impossível.

Gerenciamento do ciclo de vida

O Permission Handler deve levar em conta o ciclo de vida da Activity e do Fragment. Os launchers são registrados no ActivityResultRegistry, que salva e restaura automaticamente o estado ao girar a tela ou recriar a Activity. O handler não deve armazenar referências diretas à Activity ou Fragment — em vez disso, use WeakReference ou passe o registry pelo construtor. Isso evita vazamentos de memória e falhas durante mudanças de configuração.

Implementando Permission Handler em Kotlin

Uma implementação básica de Permission Handler é construída sobre ActivityResultContracts.RequestPermission. O handler recebe o ActivityResultRegistry de ComponentActivity ou Fragment e registra launchers para cada permissão. Cada launcher aceita uma lambda de callback que é invocada após a resposta do usuário.

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

Inicialização na Activity

O handler é inicializado no onCreate da Activity via registerForActivityResult, que fornece acesso ao ActivityResultRegistry. Após a inicialização, o handler está pronto para processar solicitações durante todo o ciclo de vida da Activity. É importante chamar initialize antes da primeira solicitação, caso contrário o launcher não será registrado.

Permission Handler com ViewModel

Integrar um Permission Handler com ViewModel é a abordagem mais avançada. O ViewModel gerencia o estado das solicitações, enquanto o Handler apenas realiza chamadas de plataforma. O ViewModel contém StateFlow<PermissionUiState>, onde UiState descreve qual permissão está sendo solicitada e qual resultado foi recebido. A Activity se inscreve neste StateFlow e delega a solicitação ao 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()
}

Neste modelo, a Activity verifica isPermissionGranted através do Handler na inicialização, enquanto o ViewModel apenas gerencia o estado. Se a permissão não for concedida — a Activity se inscreve no uiState, chama requestCamera do Handler e passa o resultado de volta ao ViewModel via onPermissionResult. Separar o código de plataforma da lógica de negócios permite testar o ViewModel sem dependências do Android.

Testando Permission Handler

Os testes unitários de Permission Handler são possíveis graças à interface PermissionHandler. Nos testes, um FakePermissionHandler é criado para simular vários cenários: permissão concedida, negada, Never Ask Again. Cada cenário é testado independentemente. Isso é especialmente importante para testar a lógica de UI que deve reagir corretamente a todos os três 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
    }
}

A implementação fake permite testar o ViewModel sem um emulador. Basta definir cameraResult para o valor desejado e verificar se o ViewModel atualiza corretamente seu UiState. Os testes de integração verificam o PermissionHandler real com ActivityScenario, mas normalmente há apenas 2-3 desses testes por aplicativo — os cenários restantes são cobertos por testes unitários com fakes.

Padrões comuns e erros

Os erros típicos ao trabalhar com Permission Handler incluem: não verificar checkSelfPermission antes de cada chamada de API, ignorar shouldShowRequestPermissionRationale, chamar requestPermissions novamente após Never Ask Again e armazenar launchers sem considerar o ciclo de vida da Activity. Vamos examinar cada problema e sua solução.

O erro mais comum é chamar uma API sem verificar o status da permissão. Os desenvolvedores assumem que, se uma permissão foi concedida uma vez, ela permanecerá para sempre. No entanto, o usuário pode revogá-la através das configurações a qualquer momento. Um Permission Handler deve sempre chamar isPermissionGranted antes de realizar uma operação sensível. O segundo erro popular é ignorar shouldShowRequestPermissionRationale e repetir a solicitação, o que leva a uma negação instantânea sem diálogo no modo Never Ask Again.

As melhores práticas incluem: criar uma única instância de Handler para todo o ciclo de vida da Activity, usar SharedFlow para passar resultados ao ViewModel, registrar todas as solicitações e negações para análise e exibir um diálogo de justificativa personalizado antes do diálogo do sistema na primeira negação. Seguir essas regras garante um tratamento estável de permissões em todas as versões do Android.

Perguntas frequentes

O que é Permission Handler no Android?

Permission Handler é um componente para gerenciamento centralizado de permissões em tempo de execução, encapsulando checkSelfPermission, requestPermissions e shouldShowRequestPermissionRationale. Simplifica a manutenção do código e melhora os testes.

Qual API usar para Handler em 2024?

Recomenda-se usar ActivityResultContracts.RequestPermission da biblioteca androidx.activity. Ele substitui o obsoleto onRequestPermissionsResult e fornece uma API de callback limpa com resultado Boolean.

É necessário um Handler para uma única permissão?

Para uma única permissão, um Handler não é obrigatório — você pode usar uma chamada direta ao launcher RequestPermission na Activity. Um Handler torna-se necessário com 3 ou mais permissões para evitar duplicação de código.

Como testar um Permission Handler?

Crie uma interface PermissionHandler e sua implementação fake para testes unitários. O fake retorna resultados predefinidos sem chamadas de sistema. Isso permite testar a ViewModel e a lógica de UI sem emulador.

Como lidar com Never Ask Again em um Handler?

Após a negação, verifique shouldShowRequestPermissionRationale. Se o método retornar false — o modo Never Ask Again está ativo. O Handler deve retornar PermissionResult.DENIED(false), e a UI deve mostrar um botão para ir às Configurações.

Resumo

  • Permission Handler é um componente arquitetural para gerenciamento centralizado de permissões em tempo de execução do Android.
  • Baseia-se em ActivityResultContracts.RequestPermission da biblioteca androidx.activity.
  • Uma interface com métodos para cada permissão simplifica os testes unitários através de implementações fake.
  • A integração com ViewModel via StateFlow separa o código de plataforma da lógica de negócios.
  • Erros típicos: falta de checkSelfPermission, ignorar rationale e Never Ask Again.
  • Melhor prática — um Handler por Activity registrado no onCreate.
  • A centralização reduz o número de bugs Permission Denial em 60 por cento em projetos típicos.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também