Flutter: Publicação Multiplataforma e Revisão de Loja

📋 Pré-requisitos: Você deve ter dominado o seguinte primeiro

1. O Que Você Vai Aprender


2. Uma História Real de uma Submissão Rejeitada


3. Processo de Publicação Multiplataforma


4. Publicação Android


5. Publicação iOS


6. Publicação Web


7. Conformidade de Privacidade


8. Exemplo Completo: Checklist de Publicação do ShopApp


9. Checklist de Release do ShopApp v1.2.3

Depois que Bob se preparou usando o checklist, tanto a App Store quanto o Google Play passaram na primeira submissão, e a versão Web ficou no ar em 1 hora.

100%
graph TD
    REL[Release Process] --> ANDROID2[Android AAB]
    REL --> IOS2[iOS IPA]
    REL --> WEB2[Web PWA]
    ANDROID2 --> PC[Play Console]
    IOS2 --> ASC[App Store Connect]
    WEB2 --> FH[Firebase Hosting / Vercel]
    PC --> REVIEW1[Revisão Google]
    ASC --> REVIEW2[Revisão Apple]
    REVIEW1 --> LIVE1[No ar no Google Play]
    REVIEW2 --> LIVE2[No ar na App Store]
    FH --> LIVE3[No ar na Web]

(1) Assinatura e Build

▶ Exemplo: Gerar Keystore

BASH
# Gerar keystore de assinatura
keytool -genkey -v -keystore shopapp-release.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias shopapp

# Verificar keystore
keytool -list -v -keystore shopapp-release.jks -alias shopapp

Configuração de Assinatura no build.gradle

GROOVY
// android/app/build.gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    defaultConfig {
        applicationId "com.shopapp.app"
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 42
        versionName "1.2.3"
    }
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['keyFile'] ? file(keystoreProperties['keyFile']) : null
            storePassword keystoreProperties['keyPassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

Build e Publicação

BASH
# Build release AAB (Android App Bundle)
flutter build appbundle --release
# Saída: build/app/outputs/bundle/release/app-release.aab

# Build release APK (para testes)
flutter build apk --release

# Upload para o Play Console manualmente ou via CI/CD

(2) Checklist de Lançamento no Play Console

Item Requisito
ID do Aplicativo Nome de pacote único com.shopapp.app
Arquivo AAB Bundle de release assinado
Ícone 512x512 PNG
Screenshots 2-8 cada para telefone + tablet de 7 polegadas
URL da Política de Privacidade Deve estar acessível
Classificação de conteúdo Completar questionário IARC
Público-alvo Selecionar faixa etária

(1) Configuração Apple Developer

Passo Ação
1. Registro Apple Developer Program ($99/ano)
2. Certificado Criar Distribution Certificate
3. Profile Criar App Store Provisioning Profile
4. App ID Registrar Bundle Identifier
5. App Record Criar app no App Store Connect

Configuração de Build no Xcode

XML
<!-- ios/Runner/Info.plist -->
`<key>`CFBundleShortVersionString</key>
`<string>`1.2.3</string>
`<key>`CFBundleVersion</key>
`<string>`42</string>
`<key>`NSAppTransportSecurity</key>
`<dict>`
    `<key>`NSAllowsArbitraryLoads</key>
    `<false/>`
`</dict>`
`<key>`NSUserTrackingUsageDescription</key>
`<string>`Usamos rastreamento para personalizar sua experiência de compra.</string>

Build e Upload

BASH
# Build IPA
flutter build ipa --release \
  --export-options-plist=ios/ExportOptions.plist
# Saída: build/ios/ipa/shopapp.ipa

# Upload via Xcode ou linha de comando
xcrun altool --upload-app \
  --type ios \
  --file build/ios/ipa/shopapp.ipa \
  --apiKey YOUR_API_KEY \
  --apiIssuer YOUR_ISSUER_ID
# Ou via app Transporter

(2) Checklist de Lançamento no App Store Connect

| Bundle ID | Deve corresponder ao projeto Xcode | | Arquivo IPA | Build de release | | Screenshots | 6.7"/6.5"/5.5" três tamanhos | | Vídeo de preview | Opcional, ≤30s | | Descrição | ≤4000 caracteres |

▶ Exemplo: Conformidade com Apple Privacy List

DART
import 'package:flutter/material.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:firebase_analytics/firebase_analytics.dart';

// Dependências: app_tracking_transparency: ^0.2.0, firebase_analytics: ^10.0.0 (adicione às dependências)

Future<void> requestTrackingPermission() async {
  final status = await AppTrackingTransparency.requestTrackingAuthorization();
  if (status == TrackingStatus.authorized) {
    await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
  } else {
    await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(false);
  }
}

Saída:

TEXT
Diálogo App Tracking Transparency exibido
Status: authorized (ou denied)
Coleta de analytics habilitada/desabilitada conforme o status

(1) Comparação de Requisitos de Conformidade

Plataforma Itens Obrigatórios
Google Play Política de Privacidade / Data Safety Form / Classificação de Conteúdo
App Store Política de Privacidade / ATT / Declaração de Conformidade de Criptografia
Web (PWA) Consentimento de Cookies GDPR / Política de Privacidade

(2) Checklist de Conformidade de Privacidade

Verificações Pré-release

Checklist de Publicação em Três Plataformas

(1) Android

(2) iOS

(3) Web

(4) Pós-release

❓ Perguntas Frequentes

P: Qual a diferença entre AAB e APK? R: AAB (Android App Bundle) é o formato de upload — o Google Play gera automaticamente APKs otimizados a partir dele. AABs são menores porque incluem apenas os recursos necessários pelo dispositivo.

P: Quanto tempo leva a revisão da App Store geralmente? R: Primeiras submissões geralmente levam 24-48 horas, atualizações geralmente 12-24 horas. Re-submissões após rejeição exigem outra espera.

P: Como devo gerenciar versionCode e versionName? R: versionCode deve ser um inteiro incremental (+1 para cada release); versionName é visível ao usuário (ex: 1.2.3). Use convenções SemVer.

P: A versão Web precisa de registro ICP? R: Servidores na China continental exigem registro ICP. Servidores no exterior (Firebase/Vercel) não.

P: O que a conformidade GDPR exige? R: 1) Mostrar consentimento de privacidade no primeiro lançamento; 2) Fornecer opção de exclusão de dados; 3) Link da política de privacidade; 4) Minimizar coleta de dados; 5) Usuários podem revogar consentimento.

P: O que devo fazer se a App Store rejeitar minha submissão? R: Leia cuidadosamente o motivo da rejeição, corrija os problemas e reenvie. Motivos comuns: política de privacidade ausente, popup ATT não exibido, crashes, violações de política de conteúdo.


📖 Resumo


(1) Exemplo: Cadência de Release de Número de Versão

TEXT
1.0.0  →  Lançamento MVP (primeiro release)
1.0.1  →  Correção urgente de bug (patch)
1.1.0  →  Nova funcionalidade (minor)
1.2.3  →  Release do ShopApp (minor + patch)
2.0.0  →  Refatoração maior (major)

Saída:

TEXT
SemVer: MAJOR.MINOR.PATCH
- MAJOR mudanças incompatíveis
- MINOR adições compatíveis
- PATCH correções compatíveis

(2) Exemplo: Integração Firebase Crashlytics

DART
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'dart:ui' show PlatformDispatcher;

// Dependências: firebase_core: ^2.0.0, firebase_crashlytics: ^3.0.0 (adicione às dependências)
// ShopApp vem do projeto lib/app.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FlutterError.onError = (details) {
    FirebaseCrashlytics.instance.recordFlutterFatalError(details);
  };

  PlatformDispatcher.instance.onError = (error, stack) {
    FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
    return true;
  };

  runApp(const ShopApp());
}

Saída:

TEXT
Crashlytics inicializado
Erros fatais reportados automaticamente
Erros não-fatais reportados automaticamente

(3) Exemplo: Dashboard de Monitoramento de Release

BASH
# Firebase Crashlytics
firebase functions:log --only publishMonitor
# Saída esperada:
# {"status":"ok","version":"1.2.3","crashRate":"0.05%"}

Saída:

TEXT
Taxa de crash após rollout:
- 1h: 0.05% (baseline 0.10%)
- 24h: 0.04% (saudável)
- Taxa ANR: 0.01% (aceitável)

📝 Exercícios

  1. Básico (dificuldade ⭐): Gere um Android Keystore para o ShopApp, configure a assinatura no build.gradle, e faça build com sucesso de um AAB de release.
  2. Intermediário (dificuldade ⭐⭐): Complete a preparação de publicação dual-plataforma do ShopApp — assinatura Android AAB + configuração de certificado iOS, e escreva um checklist de publicação multiplataforma.
  3. Desafio (dificuldade ⭐⭐⭐): Implemente o processo completo de publicação multiplataforma do ShopApp (Android + iOS + Web), incluindo declarações de conformidade de privacidade, geração de screenshots multicanal e escrita de descrição para a App Store.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%