Build e distribuição em React Native: Android e iOS com ícones, splash e versões

Capítulo 15

Tempo estimado de leitura: 11 minutos

+ Exercício

O que significa “build” e “distribuição” no React Native

Em React Native, “build” é o processo de transformar seu código JavaScript/TypeScript e configurações nativas em um artefato instalável: no Android, geralmente APK (instalação direta) ou AAB (publicação na Play Store); no iOS, um .ipa gerado a partir de um Archive no Xcode para distribuição via TestFlight/App Store ou instalação interna. “Distribuição” é o conjunto de passos para assinar, versionar, empacotar e entregar esse artefato para testes ou lojas.

Variantes de build: debug vs release (e flavors quando necessário)

Debug

  • Focado em desenvolvimento: logs, ferramentas de depuração, e geralmente usa servidor Metro.
  • No Android, é assinado automaticamente com uma chave de debug do sistema.
  • No iOS, costuma rodar via Xcode em modo Debug com assinatura de desenvolvimento.

Release

  • Focado em distribuição: otimizações, minificação (quando aplicável), sem ferramentas de debug.
  • Exige assinatura com credenciais de produção (Android keystore / iOS certificados e provisioning).
  • Gera artefatos para loja ou distribuição interna.

Flavors (Android) e Schemes/Configurations (iOS)

Se você precisa de múltiplos ambientes (ex.: dev, staging, prod) com IDs, ícones ou endpoints diferentes, no Android isso é feito com productFlavors e no iOS com Schemes e Build Configurations. Mesmo sem flavors, entender a separação debug/release já cobre a maior parte dos casos.

Android: assinatura, versionamento e geração de APK/AAB

1) Ajuste de versionCode e versionName

No Android, o versionamento é controlado principalmente em android/app/build.gradle (ou android/app/build.gradle.kts em Kotlin DSL). Dois campos são críticos:

  • versionName: versão “humana” (ex.: 1.4.0).
  • versionCode: inteiro incremental obrigatório para a Play Store (ex.: 10400).

Exemplo (Groovy):

android {  defaultConfig {    applicationId "com.suaempresa.seuapp"    minSdkVersion rootProject.ext.minSdkVersion    targetSdkVersion rootProject.ext.targetSdkVersion    versionCode 10400    versionName "1.4.0"  }}

Boas práticas para versionCode:

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

  • Sempre incrementar a cada upload na Play Store.
  • Adotar uma regra previsível (ex.: major*10000 + minor*100 + patch).

2) Criando um keystore (chave de assinatura)

Para assinar builds de release, crie um keystore e guarde-o com segurança. Exemplo com keytool:

keytool -genkeypair -v -storetype JKS -keystore seuapp-release.keystore -alias seuapp -keyalg RSA -keysize 2048 -validity 10000

Recomendações:

  • Faça backup do arquivo .keystore e das senhas (store password e key password).
  • Não comite o keystore no repositório.
  • Use variáveis de ambiente/arquivos locais ignorados pelo Git para senhas.

3) Configurando assinatura no Gradle

Crie/edite android/gradle.properties (ou use variáveis de ambiente no CI). Exemplo (não comitar se contiver segredos):

MYAPP_UPLOAD_STORE_FILE=seuapp-release.keystore MYAPP_UPLOAD_KEY_ALIAS=seuapp MYAPP_UPLOAD_STORE_PASSWORD=******** MYAPP_UPLOAD_KEY_PASSWORD=********

Em android/app/build.gradle:

android {  signingConfigs {    release {      if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {        storeFile file(MYAPP_UPLOAD_STORE_FILE)        storePassword MYAPP_UPLOAD_STORE_PASSWORD        keyAlias MYAPP_UPLOAD_KEY_ALIAS        keyPassword MYAPP_UPLOAD_KEY_PASSWORD      }    }  }  buildTypes {    debug {      // debug usa assinatura padrão      signingConfig signingConfigs.debug    }    release {      signingConfig signingConfigs.release      minifyEnabled false      shrinkResources false      // Proguard/R8 pode ser habilitado conforme necessidade      // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'    }  }}

Observação: para Play Store, é comum usar “Upload Key” e habilitar “Play App Signing”. Assim, você assina o upload e a Play Store re-assina para distribuição.

4) Gerando AAB (Play Store) e APK (instalação direta)

Com o ambiente Android configurado, execute na pasta android:

  • Gerar AAB (recomendado para Play Store):
./gradlew bundleRelease

O arquivo costuma sair em:

android/app/build/outputs/bundle/release/app-release.aab
  • Gerar APK de release (útil para distribuição interna/QA):
./gradlew assembleRelease

O arquivo costuma sair em:

android/app/build/outputs/apk/release/app-release.apk

5) Validando o artefato Android antes de publicar

  • Instale o APK em um dispositivo real e verifique fluxo crítico (login, navegação principal, permissões).
  • Confirme se o build está em release (sem menu de dev, sem logs excessivos).
  • Verifique se o versionCode é maior que o último publicado.
  • Teste em diferentes versões do Android e densidades de tela (ícone/splash).

iOS: certificados, provisioning, versionamento e Archive

1) Version (CFBundleShortVersionString) e Build (CFBundleVersion)

No iOS, há dois valores principais:

  • Version (ex.: 1.4.0) — equivalente ao versionName.
  • Build (ex.: 57) — número incremental; deve aumentar a cada envio ao TestFlight/App Store.

Você ajusta isso no Xcode em Target > General (ou em Info.plist dependendo da configuração). Em termos de chaves:

  • CFBundleShortVersionString = Version
  • CFBundleVersion = Build

2) Certificados e Provisioning Profiles (visão prática)

Para distribuir um app iOS, você precisa alinhar três elementos:

  • Bundle Identifier (ex.: com.suaempresa.seuapp).
  • Certificado (Development ou Distribution).
  • Provisioning Profile que vincula o Bundle ID ao certificado e (no caso de desenvolvimento/ad hoc) aos dispositivos.

Fluxo comum:

  • Para testes internos: TestFlight (recomendado) usando perfil de distribuição App Store.
  • Para instalação direta em dispositivos específicos: Ad Hoc (exige listar UDIDs).

3) Assinatura no Xcode (Automatic vs Manual)

No Xcode, em Signing & Capabilities:

  • Automatic Signing: o Xcode gerencia perfis automaticamente (bom para times pequenos e fluxo simples).
  • Manual Signing: você seleciona o provisioning profile e certificado (útil em cenários corporativos/CI mais controlado).

Checklist rápido:

  • O Bundle Identifier do target corresponde ao registrado no Apple Developer.
  • O time (Team) correto está selecionado.
  • Não há conflitos de capabilities (ex.: Push Notifications, Associated Domains) sem configuração no portal.

4) Gerando Archive e distribuindo (TestFlight/App Store)

Passo a passo no Xcode:

  • Selecione o esquema do app e um destino genérico (ex.: Any iOS Device (arm64)).
  • Menu Product > Archive.
  • Ao finalizar, abra o Organizer e selecione o Archive gerado.
  • Clique em Distribute App e escolha:
    • App Store Connect para TestFlight/App Store.
    • Ad Hoc para distribuição em dispositivos listados.
    • Development para builds de desenvolvimento.

Validações importantes no upload:

  • O Build Number precisa ser maior que o último enviado para a mesma Version.
  • Ícones e splash devem estar presentes e sem transparência indevida (especialmente ícone iOS).
  • Permissões e descrições no Info.plist devem existir para recursos usados (câmera, localização etc.).

Ícones e Splash: estratégia de assets e geração

Conceitos: App Icon vs Splash Screen

  • App Icon: ícone exibido na home, app switcher e loja. Precisa de múltiplos tamanhos e regras específicas por plataforma.
  • Splash Screen: tela inicial enquanto o app carrega. No iOS e Android modernos, é recomendado usar uma abordagem nativa simples (fundo + logo central) para evitar “piscar” e inconsistências.

Organização recomendada de arquivos

  • Mantenha fontes em alta resolução em uma pasta de design, por exemplo: assets/branding/icon.png e assets/branding/splash.png.
  • Evite editar manualmente dezenas de tamanhos; prefira geração automatizada.

Geração automática com biblioteca (exemplo prático)

Uma abordagem comum é usar uma biblioteca que gere ícones e splash a partir de um arquivo fonte. Um exemplo popular é react-native-bootsplash para splash (e pode ser combinado com geradores de ícone). Fluxo típico:

  • Adicionar a dependência e seguir o guia da biblioteca para integrar no Android e iOS.
  • Gerar assets a partir de uma imagem fonte e uma cor de fundo.

Exemplo de comando (varia conforme a ferramenta escolhida):

npx react-native-bootsplash generate --platforms=android,ios --background=FFFFFF --logo=assets/branding/splash-logo.png

Para ícones, você pode usar geradores específicos (CLI) que criam os tamanhos e colocam nos diretórios corretos. O ponto-chave é: defina um único arquivo fonte (quadrado, alta resolução) e gere os tamanhos automaticamente para evitar inconsistência.

Regras práticas para ícones

  • Use PNG quadrado em alta resolução (ex.: 1024x1024) como fonte.
  • Evite bordas “coladas”; deixe margem de respiro para diferentes máscaras.
  • No iOS, evite transparência no ícone final (pode causar rejeição/alertas).
  • No Android, considere ícone adaptativo (foreground/background) quando aplicável.

Regras práticas para splash

  • Prefira fundo sólido e logo central, sem textos.
  • Garanta contraste suficiente e teste em telas pequenas e grandes.
  • Evite imagens enormes como splash completo; isso aumenta tempo de carregamento e pode distorcer.

Permissões e configurações: AndroidManifest e Info.plist

Android: AndroidManifest.xml

Permissões devem refletir exatamente o que o app usa. Exemplos comuns:

<manifest ...>  <uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.CAMERA" />  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  <application ...>    ...  </application></manifest>

Pontos de atenção:

  • Algumas permissões exigem declarações adicionais (ex.: recursos de localização em background, notificações, etc.).
  • Remova permissões não utilizadas para reduzir fricção em revisão e aumentar confiança do usuário.
  • Verifique android:exported em componentes quando exigido por versões recentes do Android (especialmente se houver intent-filters).

iOS: Info.plist

No iOS, além de permissões, você precisa fornecer descrições (strings) exibidas ao usuário. Exemplos:

<key>NSCameraUsageDescription</key> <string>Precisamos da câmera para ...</string> <key>NSLocationWhenInUseUsageDescription</key> <string>Usamos sua localização para ...</string> <key>NSPhotoLibraryUsageDescription</key> <string>Precisamos acessar suas fotos para ...</string>

Pontos de atenção:

  • Se o app acessa um recurso e a chave não existe, o app pode crashar ao solicitar a permissão.
  • As descrições devem ser claras e específicas (evite textos genéricos).

Checklist de validação antes de publicar

Checklist geral (Android e iOS)

  • Versão e build incrementados (versionCode/versionName, Version/Build).
  • Build em modo release (sem dev menu, sem endpoints de teste, sem chaves de debug).
  • Ícone e splash revisados em dispositivos reais.
  • Permissões mínimas necessárias e descrições corretas.
  • Testes de fluxo crítico: login, onboarding, navegação principal, logout, modo offline (se aplicável).
  • Validação de API keys/segredos: não expor chaves sensíveis no app (quando aplicável, use backend/proxy).

Checklist Android específico

  • AAB gerado e assinado corretamente.
  • Verificar minSdkVersion/targetSdkVersion conforme exigências atuais.
  • Conferir se o applicationId está correto (e não é o de staging).

Checklist iOS específico

  • Archive gerado com assinatura de distribuição.
  • Bundle Identifier correto e capabilities configuradas.
  • Build number incrementado para cada upload ao TestFlight.

Troubleshooting prático de builds (erros comuns e como atacar)

1) “Funciona no debug, quebra no release”

  • Confirme se o app não depende de logs/flags de debug.
  • Verifique se endpoints e variáveis de ambiente estão corretos para release.
  • No Android, se habilitar minificação (R8/Proguard), pode ser necessário adicionar regras em proguard-rules.pro para bibliotecas específicas.

2) Erros de assinatura no Android

  • Keystore não encontrado: confira caminho do arquivo e se está acessível no ambiente atual.
  • Senha/alias inválidos: valide storePassword, keyPassword e keyAlias.
  • Upload rejeitado na Play Store: confirme se o versionCode aumentou e se você está usando a chave de upload correta (Play App Signing).

3) Erros de certificados/provisioning no iOS

  • No matching provisioning profiles found: o Bundle ID não bate com o profile, ou o profile não inclui o certificado atual.
  • Team/Signing mismatch: selecione o Team correto e re-gere perfis se necessário.
  • Capabilities faltando: habilite a capability no portal e no Xcode (ex.: Push, Sign in with Apple).

4) Build falha por cache/estado do projeto

Quando alterações de dependências ou configurações nativas geram erros estranhos, um reset de caches costuma ajudar. Exemplos de ações comuns:

  • Android: limpar build do Gradle:
cd android && ./gradlew clean
  • iOS: limpar build no Xcode (Product > Clean Build Folder) e, se aplicável, reinstalar pods.
  • Reinstalar dependências JS e reconstruir (quando houver inconsistência).

5) Problemas com ícones/splash não atualizando

  • Confirme que os assets foram gerados nos diretórios corretos (mipmap/drawable no Android, Assets.xcassets no iOS).
  • Limpe build e reinstale o app no dispositivo (ícones podem ficar cacheados).
  • Verifique se o nome do asset e referências nativas estão corretos.

Organizando um pipeline manual de release (passo a passo repetível)

1) Preparação de versão

  • Defina a versão (ex.: 1.4.0) e incremente:
    • Android: versionName e versionCode.
    • iOS: Version e Build.
  • Garanta que ícones/splash estão finalizados e aplicados.

2) Build Android

  • Atualize credenciais de assinatura (se necessário) e confirme que o keystore está disponível.
  • Gere AAB para Play Store:
cd android && ./gradlew bundleRelease
  • Instale e teste um APK de release (opcional, mas recomendado para QA interno):
cd android && ./gradlew assembleRelease

3) Build iOS

  • Abra o projeto no Xcode, selecione o esquema correto.
  • Confirme assinatura e Team.
  • Atualize Version/Build.
  • Gere Archive e distribua via App Store Connect (TestFlight).

4) Validação final

  • Teste o build distribuído (APK interno/TestFlight) em pelo menos 1 dispositivo por “família” (Android e iOS) e, idealmente, em versões diferentes.
  • Revise permissões solicitadas e textos de uso no iOS.
  • Confirme que o app abre sem depender do Metro e sem telas de erro.

5) Registro e rastreabilidade

  • Mantenha um registro simples por release: versão, build, data, hash do commit, e observações de mudanças de configuração nativa (ícone/splash/permissões).
  • Se usar múltiplos ambientes, registre qual flavor/scheme foi distribuído.

Agora responda o exercício sobre o conteúdo:

Ao preparar um app React Native para publicação, qual alternativa descreve corretamente a diferença entre build de debug e build de release?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Debug prioriza desenvolvimento (logs, depuração e frequentemente Metro). Release é para distribuição, com otimizações e sem ferramentas de debug, exigindo assinatura com credenciais de produção para gerar artefatos para loja ou distribuição interna.

Próximo capitúlo

Projeto final em React Native Essencial: app completo integrando navegação, estado, API e recursos do dispositivo

Arrow Right Icon
Capa do Ebook gratuito React Native Essencial: criando apps completos com JavaScript e boas práticas
94%

React Native Essencial: criando apps completos com JavaScript e boas práticas

Novo curso

16 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.