Guideline 2.3.1: recursos ocultos e atualizações OTA
Por Mehdi Azizi
Publicado em , 9 min
Guideline 2.3.1: a Apple recusa qualquer recurso oculto, inativo ou fora das notas de revisão. O que dá para mudar remotamente e o que exige um build.
A guideline 2.3.1 proíbe recursos ocultos, inativos ou não documentados: tudo o que o seu app faz precisa estar visível para o usuário e para o revisor. Cada novidade deve ser descrita com precisão nas notas de revisão. Uma atualização remota pode corrigir o que a Apple viu, nunca adicionar o que a Apple não viu.
Eu publico meus apps iOS com Expo, e todos vêm com EAS Update desde o primeiro build para entregar correções. Minha regra: nenhuma atualização remota enquanto uma versão está em revisão. Este guia se baseia no texto da Apple, na licença dela, na documentação do Expo e em rejeições publicadas.
O que diz a guideline 2.3.1?
A 2.3.1 abre a parte 2.3 "Accurate Metadata" das App Review Guidelines, na seção 2 "Performance". O texto começa assim: "Don't include any hidden, dormant, or undocumented features in your app; your app's functionality should be clear to end users and App Review." Traduzindo: nada escondido, adormecido ou não documentado.
O restante vale para cada envio: "All new features, functionality, and product changes must be described with specificity in the Notes for Review section of App Store Connect (generic descriptions will be rejected) and accessible for review." Cada novidade precisa ser descrita com precisão nas notas de revisão e estar acessível para o revisor. Ou seja, "Correções de bugs e melhorias" não basta.
O mesmo parágrafo trata do marketing enganoso: prometer um conteúdo ou serviço que não existe, ou exibir um preço falso, na App Store ou em qualquer outro lugar.
Essa parte me ajudou no Nolera. Relendo a página do app antes do lançamento, encontrei duas frases impossíveis de verificar: "interface somente em francês", que tinha deixado de ser verdade, e "o pacote mais escolhido", para um app que nunca tinha sido publicado. As notas para o revisor também descreviam um estado desatualizado do produto. É exatamente isso que essa parte cobre. Já a 2.3.10 mira principalmente a página do app.
O que significa a mensagem de rejeição 2.3.1?
A rejeição se chama "Guideline 2.3.1 - Performance", às vezes seguida de "Hidden Features". Duas mensagens publicadas por desenvolvedores React Native:
- Março de 2024, em uma issue do CodePush no GitHub: "The app contains hidden features.", sem mais detalhes. O desenvolvedor pede esclarecimentos e recebe um complemento com base na 2.5.2: "Your app, extension, or linked framework appears to contain code designed explicitly with the capability to change the app's behavior or functionality after App Review approval." A issue não diz se o app foi aprovado depois.
- Fevereiro de 2023, em outra issue, a Apple aponta o "CodePush-related remote code downloading/updating support" do binário.
Minha leitura: o revisor não vê as suas atualizações, ele vê o código capaz de recebê-las. Esses dois casos envolvem o CodePush. Não encontrei nenhuma rejeição pública recente envolvendo o EAS Update, o que não prova nada.
Atualizações remotas: o que a 2.5.2 e a licença permitem
A regra 2.5.2, que também abordo no guia sobre modos em segundo plano, proíbe o app de "download, install, or execute code which introduces or changes features or functionality of the app".
O artigo 3.3.1(B) do Apple Developer Program License Agreement proíbe código executável baixado, mas esclarece: "Interpreted code may be downloaded to an Application". Com três condições: esse código não muda o propósito principal do app, não contorna a assinatura, o sandbox nem as proteções do sistema, e não cria uma loja de outros apps.
O JavaScript de um app Expo é código interpretado: na minha visão, o EAS Update se encaixa nisso. A documentação dele lembra que as atualizações seguem as regras da App Store e que "changes to your app's behavior need to be reviewed". Para um bug crítico, o Expo sugere a correção remota e depois um novo envio que a inclua.
Minha linha: corrigir e ajustar o que já existe, sim. Mudar o que o app é ou o que ele vende, não.
O que dá para mudar remotamente e o que exige um novo build
A tabela que eu sigo, tirada das páginas da Apple e do Expo citadas aqui. A linha "gratuito que vira pago" e as duas últimas são interpretação minha.
| Mudança | Caminho | Por quê |
|---|---|---|
| Bug de JavaScript | Atualização remota | Uso previsto pelo Expo |
| Texto, tradução, estilo | Atualização remota | Uso previsto pelo Expo |
| Preço de uma assinatura | App Store Connect | Nenhum código alterado |
| Texto promocional | App Store Connect | Sem novo envio |
| Compra de um tipo já aprovado | Revisão só da compra | Regra do App Store Connect |
| Primeira compra de um tipo | Nova versão | Regra do App Store Connect |
| Novo recurso | Nova versão | 2.3.1 e 2.5.2 |
| Gratuito que vira pago | Nova versão | Página e notas a revisar |
| Permissão, Info.plist | Novo build | Arquivo do binário |
| Módulo nativo, SDK do Expo | Novo build | Código nativo alterado |
| Chave que desativa | Configuração remota | Tolerado se temporário |
| Chave que revela | Proibido | Recurso nunca revisado |
O texto promocional pode ser alterado "without requiring an updated submission", segundo a página da Apple sobre informações da versão. A primeira compra de cada tipo vai junto com uma nova versão, as seguintes vão sozinhas, segundo a ajuda sobre envio de compras. O Expo coloca código nativo, permissões e versão do SDK entre o que exige um novo binário, como no caso do ITMS-90683. Uma chave que desativa um recurso com problema não adiciona nada inédito, desde que não tire o que os assinantes pagaram.
Chaves remotas sem rejeição
Uma chave remota, ou feature flag, não é proibida por si só: tudo depende do que ela esconde. Minhas regras:
- Tudo o que uma chave pode exibir está presente e ativado para o revisor, e citado nas notas de revisão.
- Um teste A/B compara duas variantes que o revisor consegue ver, nunca uma variante revisada e uma inédita.
- Nenhum código detecta a revisão para se comportar de outro jeito. Essa é a própria definição de recurso oculto.
- Um paywall controlado remotamente só mostra produtos aprovados, e cada variante respeita a regra 3.1.2.
Modo demo e contas de teste
A guideline 2.1 exige uma conta de demonstração se o seu app tem login, com o servidor no ar. Se obrigações legais ou de segurança impedem você de fornecer uma, um modo demo integrado pode substituí-la, mas só "with prior approval by Apple", e ele precisa mostrar todos os recursos. A página da Apple sobre informações da versão acrescenta: a conta não pode expirar, e contas adicionais vão nas notas, limitadas a 4.000 bytes.
A ligação com a 2.3.1: um modo demo ou uma conta de teste que abre telas que, de outra forma, ficariam invisíveis precisa ser descrito. Um gesto secreto, um código ou uma conta especial não informada é um recurso oculto. Cite cada acesso especial nas notas, com o que ele libera.
Minha regra: nenhuma atualização remota durante uma revisão
Por que o EAS Update está em todos os meus apps: no Solys, meu despertador, um bug de JavaScript deixava o app mudo assim que um efeito sonoro falhava uma vez. A correção cabia em três linhas, mas era preciso um build completo e uma revisão para entregá-la. Desde então, todos os meus apps vêm com expo-updates desde o primeiro build: é um módulo nativo, e um binário compilado sem ele nunca vai receber nada. Minha configuração, no app.json:
{
"expo": {
"runtimeVersion": { "policy": "fingerprint" },
"updates": { "fallbackToCacheTimeout": 0, "checkAutomatically": "ON_LOAD" }
}
}
Com fingerprint, uma atualização só chega aos binários cujo código nativo corresponde (versões de runtime). Mas, enquanto uma versão aguarda ou passa pela revisão, eu não publico nada. Dois motivos.
- O revisor não veria a correção. Com
fallbackToCacheTimeoutem 0, uma instalação nova inicia com o código embutido e aplica a atualização no lançamento seguinte (documentação do expo-updates). O revisor instala, abre uma vez e testa o binário. O Nolera foi rejeitado com uma correção já entregue remotamente: conto essa história no guia da 2.1. - O que o revisor testa precisa continuar sendo o que os usuários recebem. Mudar o comportamento durante a revisão cria uma diferença entre a versão vista e a versão entregue.
Notas de revisão precisas
A 2.3.1 recusa descrições genéricas. O modelo que eu usaria, em inglês:
What's new in this version:
- [Feature]: [where to find it, how to test it].
Remote configuration:
- "[flag]" controls [feature]. It is ON for review.
Over-the-air updates:
- The app uses expo-updates for bug fixes only.
No update will be published during this review.
Demo account: see Sign-in information. It never expires.
Como responder a uma rejeição 2.3.1?
Responda no App Store Connect, onde você responde à mensagem do App Review.
- A mensagem continua vaga: pergunte qual recurso está em questão, como fez o desenvolvedor da issue de 2024.
- Um recurso real está mal descrito: informe o caminho exato e um vídeo curto, depois complete as notas.
- Uma chave revela algo inédito: remova-a, ou ative-a e descreva-a, depois faça um novo build.
- O código de atualização é o problema: explique que ele serve para correções, dentro do artigo 3.3.1(B). Na issue de 2023, a Apple pedia para removê-lo.
O checklist da 2.3.1 antes do envio
- Cada novidade da versão está descrita nas notas, com o caminho até ela.
- Cada chave remota está ativada para a revisão e citada nas notas.
- Nenhum código muda de comportamento para o revisor.
- Os acessos especiais estão descritos: modo demo, conta de teste, gesto.
- A página e o paywall não prometem nada que o build não faz.
- Nenhuma atualização remota é publicada durante a revisão.
Revise seu envio antes de mandar
O Review Kit reúne meu checklist antes do envio, modelos de notas para o revisor e skills do Claude Code que revisam o seu projeto. Se quiser um olhar humano, agende uma hora comigo: a gente revisa juntos suas notas de revisão e sua configuração de atualizações, por videochamada. O passo a passo completo está na página app rejeitado pela Apple.
Está preparando seu primeiro lançamento? Faça seu diagnóstico gratuito: ele coloca as etapas na ordem certa e te envia meu checklist anti-rejeição da Apple.
Perguntas frequentes
O que significa "Guideline 2.3.1 - Performance - Hidden Features"?
A Apple considera que o seu app tem um recurso oculto, inativo ou ausente das notas de revisão. A mensagem também pode se referir a um código capaz de mudar o app depois da revisão, às vezes junto com uma rejeição 2.5.2.
O EAS Update é permitido pela Apple?
A licença permite código interpretado baixado, desde que ele não mude o propósito principal do app. Corrigir, sim. Adicionar um recurso não revisado, não.
Dá para usar feature flags em um app iOS?
Sim, se tudo o que elas podem exibir já foi revisado. Ative cada chave para a revisão e descreva-a nas notas.
É preciso informar um modo demo ao revisor?
Sim. Um modo demo integrado exige aprovação prévia da Apple e precisa mostrar todos os recursos.
Dá para publicar uma atualização remota durante a revisão?
Nada proíbe isso explicitamente. Mas o revisor não a veria no primeiro lançamento, e ela cria uma diferença em relação à versão revisada. Eu sempre evito.

