Introdução: O player "quebrado" no Android 12 e superior
\nImagine: você publica com orgulho uma atualização do seu aplicativo de player ou cliente de podcast. Passam-se alguns dias e, na seção de comentários, aparecem mensagens furiosas: "Depois da atualização, a música parou de tocar!", "Os botões na tela bloqueada não funcionam!", "O aplicativo fecha ao tentar iniciar uma faixa!". Parece familiar? Muito provavelmente, você se deparou com aquele erro que atormenta milhares de desenvolvedores em todo o mundo:
\nMediaSessionCompat: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent\nEste problema é uma das perguntas mais populares no Stack Overflow (dezenas de milhares de visualizações) e está diretamente relacionado às mudanças no Android 12 (API level 31). A boa notícia: a correção é simples e levará no máximo 10 minutos. Neste artigo, vamos analisar as causas do erro, a solução correta em Kotlin e as melhores práticas para que seu aplicativo volte a funcionar perfeitamente.
\n\nPor que o erro ocorre? Entendendo o PendingIntent
\nPara entender a essência do problema, precisamos lembrar como funciona o MediaSessionCompat. Este é um componente que permite que seu aplicativo interaja com os controles de mídia do sistema: botões do fone de ouvido, tela de bloqueio, painel de notificações. Para isso, ele cria um PendingIntent — uma espécie de "chamada adiada" para os serviços do sistema. O sistema usa este Intent para dizer ao seu aplicativo: "O usuário pressionou Play/Pause/Avançar".
A partir do Android 12 (API 31), o Google endureceu os requisitos de segurança do PendingIntent. Antes, os desenvolvedores podiam não especificar a flag FLAG_IMMUTABLE ou FLAG_MUTABLE, e o sistema usava a variante mutável (mutable) por padrão. Agora, você é obrigado a indicar explicitamente se o sistema pode ou não alterar o conteúdo do seu Intent após sua criação. Se não fizer isso, seu aplicativo irá travar. O Android 12+ simplesmente não permitirá criar tal PendingIntent.
FLAG_IMMUTABLE vs FLAG_MUTABLE: qual escolher?
\n- \n
- FLAG_IMMUTABLE (recomendado): O Intent não pode ser alterado após a criação. É mais seguro, pois um invasor não conseguirá substituir os dados. Use esta flag em 90% dos casos, inclusive para
MediaSessionCompat. \n - FLAG_MUTABLE: O Intent pode ser alterado. Necessário apenas em casos especiais, como ao usar
NotificationCompatcom ações que exigem dados dinâmicos, ou ao trabalhar comAlarmManager. \n
Para MediaSessionCompat e notificações de mídia, sempre use FLAG_IMMUTABLE. Isso aumenta a segurança e a estabilidade do seu aplicativo.
Correção passo a passo em Kotlin
\nVamos ver como é o código típico que causa o erro e como corrigi-lo. Na maioria das vezes, o problema ocorre no método onCreate() do seu serviço ou media browser.
Código incorreto (causará travamento no Android 12+)
\n// Método antigo — sem especificar a flag\nval pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n 0 // <-- Erro! Sem FLAG_IMMUTABLE ou FLAG_MUTABLE\n)\n\nCódigo correto em Kotlin (correção)
\nBasta adicionar PendingIntent.FLAG_IMMUTABLE no último parâmetro:
val pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n PendingIntent.FLAG_IMMUTABLE // <-- Solução!\n)\nSe seu aplicativo suporta versões mais antigas do Android (abaixo da API 31), use uma verificação condicional para evitar travamentos em dispositivos antigos:
\nval flags = if (Build.VERS