Dez exemplos para coordenar lançamentos de lojas nativas com trens JavaScript OTA - a base operacional que as equipes móveis corporativas precisam antes de escalar além de um engenheiro marcando builds de sexta-feira.
Toda decisão de lançamento corporativo começa com a qual relógio a alteração pertence:
Clock A - Store binary (eas build + eas submit) Changes: native modules, SDK bumps, permissions, entitlements, icons Cadence: biweekly or monthly release train Rollback: new store version (hours to days)Clock B - OTA bundle (eas update) Changes: JS, TypeScript, assets, copy - same runtimeVersion as Clock A Cadence: daily to weekly between store trains Rollback: eas update:rollback (minutes)
Relógio
Ponto de entrada de CI
Proprietário
Impacto no usuário se mal cronometrado
A
eas build em tag
Plataforma Móvel
Crash ao iniciar, rejeição da loja
B
eas update em merge
Recurso Móvel
UI incorreta, erros de JS no binário antigo
Relógio A é lento, mas altera o "shell" nativo - Hermes, módulos nativos, entitlements de push.
Relógio B é rápido, mas não pode adicionar código nativo - apenas JS que o binário já suporta.
Todo binário de produção deve escutar no mesmo canal para o qual você publica:
# Build production binary - channel baked in at compile timeeas build --profile production --platform all --non-interactive# OTA must target the same channeleas update --channel production --environment production \ --message "fix: checkout total rounding"
# Verify alignment before every production OTAeas channel:view production# Confirm channel points at production branch and runtimeVersion matches app.config
Canais incompatíveis causam tickets de suporte "a atualização nunca chega" - não crashes.
Aplicativos white-label precisam de canais separados por ID de pacote - nunca compartilhe um único canal de produção.
Equipes corporativas mantêm um calendário compartilhado - não planilhas separadas de iOS, Android e JS:
# Release 2.5.0 - Week of 2026-07-14## Clock A (store)- Thu W1: code freeze 18:00 UTC- Fri W1: tag v2.5.0; eas build production; gated submit- Mon W2: Play staged 10% → 50%- Wed W2: ASC phased release 100%## Clock B (OTA)- Mon–Wed W1: OTA to preview channel only (behind flags)- Thu W1: freeze OTA to production until store RC signed- Wed W2: OTA hotfix lane open if runtimeVersion unchanged## Dependencies- [ ] API v3 on prod - @backend - Thu W1- [ ] Feature flag checkout_v3 at 0% - @mobile - Fri W1
Congelamento de OTA durante o RC da loja impede a deriva de JS entre a aprovação do QA e o envio.
Lane de hotfix reabre após o binário da loja estar ativo e o runtimeVersion estar estável.
O artefato testado pelo QA deve ser o artefato que as lojas recebem:
# Release pipeline records build_id in ticketeas build --profile production --platform ios --non-interactive# build_id: abc123-def456-...# QA signs off on abc123 - never rebuild before submiteas submit --platform ios --id abc123-def456-... --non-interactive
# .github/workflows/release.yml - submit pinned ID from workflow output- name: Submit iOS (pinned build) run: eas submit --platform ios --id ${{ needs.build.outputs.ios_build_id }} --non-interactive
Reconstruir entre QA e submit invalida o mapeamento de symbolication de crash e as capturas de tela de revisão.
--latest submit é apenas para emergências - documente quando é permitido.
O JS que chama uma nova API não deve ser enviado via OTA até que o backend esteja ativo:
Wrong order: OTA ships Monday → API deploys Thursday → 3 days of 404sRight order: API deploys Thursday (backward compatible) → OTA ships Friday
// src/api/checkout.ts - tolerant reader until flag rampsexport async function fetchCheckoutConfig(): Promise<CheckoutConfig> { const res = await api.get("/v3/checkout/config"); if (res.status === 404) { return api.get("/v2/checkout/config"); // fallback for old path } return res.json();}
API compatível com versões anteriores é implantada primeiro; OTA móvel habilita a UI via feature flag em segundo lugar.
Remoção de API que quebra compatibilidade requer binário da loja do Relógio A sem chamadas antigas - coordene a janela de depreciação.
Binários da loja podem ficar em revisão por dias enquanto o JS é enviado diariamente - flags desacoplam ativo de visível:
Day 1: eas build ships v2.5.0 to TestFlight - checkout_v3 flag OFFDay 3: eas update ships checkout UI - still hidden behind flagDay 5: App Review approves; staged rollout begins - flag 0%Day 7: OTA + flag ramp to 10% internal cohortDay 10: flag 100% after metrics pass
Binário ativo significa que o shell nativo está na loja - os usuários podem instalá-lo.
Recurso visível significa que a flag (ou canal) expõe a nova experiência.
Podemos enviar OTA durante a revisão da App Store?
Sim, se runtimeVersion corresponder ao binário em revisão e o OTA não alterar o comportamento que os revisores testarão. Mantenha os OTAs de produção atrás de flags até a aprovação - os revisores podem testar um build que recebe um OTA ao iniciar.
Com que frequência as equipes corporativas devem executar trens da loja?
Quinzenalmente é comum para aplicativos de consumo; mensalmente para indústrias regulamentadas. OTA preenche a lacuna entre os trens - diariamente ou semanalmente para correções de JS. Combine a cadência com o risco de revisão da loja e as janelas de dependência do backend.
Quem é o proprietário do calendário de lançamentos?
Gerente de engenharia ou capitão de lançamento - responsável. Mobile, backend, QA e suporte são consultados. O calendário vive em um documento compartilhado ou epic do Jira, não no caderno de um engenheiro.
iOS e Android precisam de envios OTA separados?
Um eas update atende a ambas as plataformas quando elas compartilham runtimeVersion e canal. Os envios para a loja permanecem por plataforma - EAS Submit.