Guideline 2.5.4: modo em segundo plano recusado pela Apple
Por Mehdi Azizi
Publicado em , 9 min
Guideline 2.5.4: a Apple recusa um modo em segundo plano declarado sem função que o use. Remova a chave ou mostre ao revisor o som, a localização ou a chamada.
A guideline 2.5.4 limita os modos em segundo plano ao uso previsto: som, localização, chamadas VoIP, conclusão de tarefas, notificações locais. A recusa vem quando o seu Info.plist declara um desses modos e o revisor não encontra nenhuma função que precise dele. Remova a chave se nada a usa; se não, mostre a função ao revisor em trinta segundos.
Eu publico meus próprios apps iOS com Expo. O Solys, meu despertador com minijogos, declara o modo de áudio: eu tirei, depois coloquei de volta por outro motivo. Este guia se apoia no texto da Apple, em recusas publicadas por outros desenvolvedores e nos meus projetos. Para a visão geral dos motivos, leia por que a Apple recusa um app.
O que diz a guideline 2.5.4?
A regra cabe em uma frase, na seção 2 "Performance", parte 2.5 "Software Requirements", das App Review Guidelines: "Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc."
Traduzindo: um serviço em segundo plano só serve para aquilo que ele existe. Daí o título "Guideline 2.5.4 - Performance - Software Requirements".
Por padrão, um app que vai para o segundo plano é suspenso. Para continuar rodando, ele declara um ou mais modos na chave UIBackgroundModes do Info.plist. A documentação da Apple sobre modos em segundo plano pede para usá-los com moderação, por causa da bateria, e preferir outra solução quando ela existir. Cada modo declarado é uma promessa que o revisor pode verificar.
Os modos em segundo plano e seu uso previsto
| Modo | Chave | Uso previsto |
|---|---|---|
| Áudio, AirPlay, PiP | audio | Som audível em segundo plano |
| Localização | location | Localização contínua |
| Voz sobre IP | voip | Chamadas com CallKit |
| Busca | fetch | Conteúdo de rede regular |
| Processamento | processing | Tarefas agendadas |
| Notificações remotas | remote-notification | Push de conteúdo novo |
Essa tabela resume a página da Apple. Nas recusas publicadas nos fóruns, audio, location e voip são os que mais aparecem.
O que quer dizer a mensagem de recusa 2.5.4?
A mensagem cita o modo em questão. Dois exemplos publicados por desenvolvedores nos fóruns da Apple:
- Áudio: "Your app still declares support for audio in the UIBackgroundModes key in your Info.plist but did not include features that require persistent audio." Na sequência, ela explica que a chave
audioé feita para apps que tocam conteúdo audível em segundo plano, como um player de música. E propõe duas saídas: adicionar esse conteúdo ou remover a chave (tópico do fórum). - Localização: em um tópico de dezembro de 2024, a Apple não encontrou nenhuma função além do rastreamento de funcionários que exigisse localização permanente, e escreveu que esse uso sozinho não é apropriado.
Minha leitura: o revisor não lê o seu código, ele procura uma função. Ele precisa conseguir abri-la, mandar o app para o segundo plano e ver que ela continua.
O caso inverso também existe. Em um tópico de maio de 2026, um app de leitura em voz alta, que usava de verdade o modo audio, foi recusado várias vezes: o revisor não conseguia disparar o som. Outro desenvolvedor escreve ali que, na opinião dele, um vídeo anexado destravou o caso dele. É um relato, não uma regra da Apple.
De onde vem a chave quando você não a adicionou?
Com Expo, são os plugins de configuração que preenchem o Info.plist no prebuild. Então um modo em segundo plano pode entrar no seu binário sem você ter decidido.
O plugin expo-audio, com a configuração padrão
A documentação do expo-audio avisa: a opção enableBackgroundPlayback vale true por padrão e, no iOS, adiciona o modo audio. Declarar o plugin na forma curta, "expo-audio", já basta para declarar o modo.
Foi o que encontrei revisando o TradaZen antes do primeiro envio: sons curtos de interface em primeiro plano, mas um plugin declarado na forma curta. A correção cabe no app.json:
{
"expo": {
"plugins": [["expo-audio", { "enableBackgroundPlayback": false }]]
}
}
Outros pacotes adicionam um modo do seu jeito. A opção isIosBackgroundLocationEnabled do expo-location só adiciona location se você ativá-la. Já o expo-background-task adiciona processing no prebuild assim que é instalado.
A pasta ios/ que guarda a chave antiga
Segunda armadilha, que vivi no Solys em julho de 2026. Eu tinha tirado audio do app.json, mas a chave continuava em ios/Solys/Info.plist, gerado antes. Um prebuild sem --clean modifica esse projeto em vez de recriá-lo, e o plugin adiciona a chave sem nunca removê-la. Um build local teria levado a chave junto. Um build EAS na nuvem parte de um prebuild novo quando ios/ é ignorado pelo git, que era o meu caso.
Antes de cada build, eu verifico o que vai sair de verdade:
npx expo config --type introspect --json | grep -o '"UIBackgroundModes":\[[^]]*\]'
npx expo prebuild --clean --platform ios
O primeiro lista os modos que o prebuild vai escrever no Info.plist. O segundo recria o projeto nativo para um build local, apagando a pasta ios/. No Solys, o primeiro mostra "UIBackgroundModes":["audio"], no TradaZen nada: os dois são intencionais.
Adicionar ou remover um modo altera o Info.plist, ou seja, o binário: é preciso um novo build, uma atualização remota não basta. A documentação do EAS Update coloca essas mudanças entre as que exigem um novo binário, como no caso do ITMS-90683.
Solys: um modo de áudio declarado, com um motivo real
O Solys é um despertador, mas o modo audio não serve para tocar o alarme: o toque passa pelo AlarmKit, o serviço de alarme da Apple disponível desde o iOS 26 (documentação do AlarmKit). Quem toca é o sistema, mesmo no modo silencioso, não o app.
O histórico da chave, porque o raciocínio importa mais que a linha:
- No fim de julho de 2026, eu tiro a chave. Nada tocava som em segundo plano: os efeitos sonoros dos minijogos ficam em primeiro plano, e o alarme não depende do app.
- Dois dias depois, coloco de volta, com a escuta da noite. Essa opção grava os ruídos da sua noite com o microfone e analisa tudo no iPhone. A gravação precisa continuar com a tela bloqueada, e a documentação do expo-audio diz que a opção de gravação em segundo plano também adiciona o modo
audio.
A justificativa mudou de natureza: o modo serve para gravar, não para tocar. Três proteções, visíveis no app:
- a escuta é uma opção desligada por padrão, que se ativa nos ajustes ou no ritual da noite;
- ela tem uma tela de consentimento própria, como exige a regra 2.5.14 para qualquer gravação, e nada sai do celular;
- o microfone fecha dez minutos antes do alarme, para que a escuta e o toque nunca se atrapalhem.
Não posso garantir que um revisor sempre vai aceitar essa declaração. Sei dizer, para cada elemento, para que ele serve e onde vê-lo.
Os despertadores que mantinham o app acordado
Antes do AlarmKit, um app de despertador de terceiros não conseguia tocar como o alarme da Apple. Então algumas bibliotecas mantinham o app acordado: a documentação do pacote Flutter alarm2 descreve um player de áudio silencioso que roda até o alarme. Só que um som mudo não faz ninguém ouvir nada. Desde o iOS 26, o AlarmKit torna esse desvio inútil.
Manter ou remover o modo: a tabela de decisão
| Sua situação | O que fazer |
|---|---|
| Sons curtos em primeiro plano | Remover audio |
| Música ou audiolivro | Manter, mostrar |
| Gravação longa | Manter + consentimento |
| Despertador ou timer | AlarmKit (iOS 26) |
| Localização de vez em quando | Mudanças significativas |
| Sincronização sem urgência | fetch ou processing |
| Chamadas de áudio ou vídeo | voip com CallKit |
Para localização, a página da Apple cita o serviço de mudanças significativas de localização como alternativa ao modo location.
Os outros itens da 2.5: 2.5.1 e 2.5.2
2.5.1: APIs públicas e frameworks no lugar certo
"Apps may only use public APIs and must run on the currently shipping OS." O app só usa APIs públicas, roda na versão atual do sistema e abandona o que está obsoleto. Como na 2.5.4, cada framework serve ao seu uso previsto, mencionado na descrição: HealthKit para saúde, HomeKit para casa conectada. Se uma biblioteca chama uma API privada, quem leva a recusa é o seu app.
2.5.2: nada de código baixado que mude o app
O app tem que ser autossuficiente no seu pacote. Ele não pode "download, install, or execute code which introduces or changes features or functionality of the app". Só apps educacionais que ensinam a programar têm uma exceção limitada, com código totalmente visível e editável pelo usuário.
Com Expo, a questão envolve o EAS Update, cuja documentação lembra que as atualizações precisam respeitar as regras da App Store. Use atualizações remotas para corrigir, nunca para entregar uma função que o revisor não viu. Uma correção ligada à revisão passa por um novo build, como explico no guia da guideline 2.1.
Como responder a uma recusa 2.5.4?
A conversa acontece na seção App Review do seu app, onde você responde à mensagem do App Review. Dois casos:
- O modo não serve para nada: remova, faça um novo build, confira a introspecção e responda em duas frases.
- O modo serve a uma função real: responda com o caminho exato e um vídeo curto, depois repita esse texto nas notas de revisão de cada versão.
O modelo que eu usaria, para adaptar (tire a frase sobre o alarme se o seu app não tiver um):
Hello,
The "audio" background mode is used only by [feature], an
optional feature that [records / plays] audio while the
device is locked. It is off by default.
How to test:
1. Open [screen] and turn on [feature].
2. Accept the microphone permission if asked.
3. Tap [button], then lock the device.
[What the reviewer will hear or see.]
Our alarm does not use this mode: it is scheduled with
AlarmKit and rings through the system.
Attached: a short screen recording of these steps.
Best regards,
O checklist 2.5.4 antes do envio
- A introspecção do Expo só mostra os modos desejados, e você sabe dizer a função de cada um.
- Nenhum plugin está declarado na forma curta se ele adiciona um modo por padrão, como o expo-audio.
- A sua pasta
ios/local não guarda nenhuma chave antiga, ou você compila a partir de um prebuild limpo. - A função dispara rápido, sem ajuste escondido, e as notas de revisão dizem qual modo serve para quê e como testar.
- Toda gravação pede consentimento explícito e mostra um indicador visível. As regras sobre pedidos de permissão estão no guia da guideline 5.1.1.
- Para um despertador, o toque passa pelo AlarmKit, não por um som tocado pelo app.
Revisar o seu projeto antes do envio
O Review Kit reúne meu checklist pré-envio, modelos de notas para o revisor e skills do Claude Code que revisam o seu projeto. Para um olhar humano, reserve uma hora comigo: a gente lê a mensagem da Apple e o seu Info.plist juntos, por videochamada. O passo a passo completo está na página app recusado pela Apple.
Está preparando seu primeiro lançamento? Faça seu diagnóstico gratuito: ele coloca as etapas em ordem e te envia meu checklist anti-recusa da Apple.
Ninguém pode garantir que a Apple vai aceitar o seu app. Já um modo em segundo plano bem justificado se defende em trinta segundos.
Perguntas frequentes
O que quer dizer "Guideline 2.5.4 - Performance - Software Requirements"?
É o título da recusa quando a Apple considera que um modo em segundo plano do seu Info.plist não está sendo usado para o fim previsto. A mensagem cita o modo e propõe mostrar a função que o usa ou remover a chave.
Preciso de um novo build depois de uma recusa 2.5.4?
Se você remover ou alterar um modo, sim: a chave está no Info.plist, ou seja, no binário. Se o modo for justificado, uma resposta com o caminho exato e um vídeo pode bastar.
Dá para manter o modo de áudio para alguns sons de interface?
Não. Sons curtos tocados em primeiro plano não precisam dele. Com Expo, defina enableBackgroundPlayback como false no plugin expo-audio.
Um app de despertador precisa do modo de áudio?
Não para tocar, se ele usar o AlarmKit, disponível desde o iOS 26: quem toca o alarme é o sistema. No Solys, o modo audio serve para a escuta da noite, que grava com a tela bloqueada.
Por que a Apple cita a 2.5.4 se eu não declarei nada?
Talvez um plugin tenha feito isso por você: o expo-audio adiciona o modo audio por padrão, e uma pasta ios/ antiga pode guardar uma chave que você tirou da configuração. Verifique com npx expo config --type introspect.

