Antes de começar
Leia esta aba inteira uma vez. Cada passo das próximas abas tem uma caixinha: marque quando terminar (fica salvo neste navegador).
Como o projeto é feito
Jogo
Site feito em React + TypeScript + Phaser, gerado pelo Vite na pastadist/. Funciona sozinho no navegador (salva no aparelho) e, com o Firebase configurado, também na nuvem.Painel do administrador
Página separada em/admin/ (não vai junto no jogo). Login com e-mail/senha ou Google, só para quem tem papel de superadmin, admin ou suporte.Servidor
Firebase: Hosting (site), Authentication (contas), Firestore (dados), Cloud Functions (banir, papéis, conferir compras, estatísticas).Android
TWA (Trusted Web Activity) gerado pelo Bubblewrap: um app da Play Store que abre o site publicado em tela cheia. Pagamentos pelo Google Play Billing.iPhone
TWA não existe no iPhone. Na App Store o caminho é o Capacitor (precisa de Mac), e a Apple exige o pagamento dela (StoreKit). Veja a aba iPhone.Uma base só
O mesmo código serve web, Android e iPhone. Atualizou o site, o app Android já mostra a versão nova (não precisa reenviar à loja).O que você vai precisar
| Item | Custo | Para quê |
|---|---|---|
| Conta Google | grátis | Firebase, Play Console |
| Firebase plano Blaze (pago por uso) | tem cota grátis; precisa de cartão | Cloud Functions e notificações do Google Play |
| Domínio próprio (fazendinharetro.com) | GoDaddy, registro.br ou outro | Endereço do jogo e do app Android |
| Conta de desenvolvedor Google Play | US$ 25 (uma vez) | Publicar o app Android |
| Perfil de pagamentos no Play Console | grátis | Vender itens no app e receber |
| Apple Developer Program + um Mac com Xcode | US$ 99 por ano | Só se for publicar no iPhone |
| Computador com Node.js 22 e Git | grátis | Rodar os comandos |
| Java JDK 17 e Android SDK | grátis (o Bubblewrap instala) | Gerar o app Android |
VITE_FIREBASE_API_KEY) é pública por natureza e vai no site. Quem protege os dados são as regras do Firestore e as Cloud Functions, que já estão prontas neste projeto. Os arquivos que nunca vão para o Git: a chave de assinatura do Android (*.keystore), senhas e o arquivo functions/.env.*.Mapa do projeto
| Arquivo / pasta | O que é |
|---|---|
.env.example | Modelo das chaves do Firebase do site (copie para .env) |
firebase.json | Hosting (site + /admin), regras, functions, emuladores |
firestore.rules / firestore.indexes.json | Quem pode ler e escrever cada dado / índices das buscas do painel |
functions/ | Cloud Functions (TypeScript): banir, papéis, compras, estatísticas |
src/admin/ e admin/index.html | Painel do administrador |
src/services/billing.ts | Pagamentos do Google Play no jogo (Digital Goods API) |
public/.well-known/assetlinks.json | Liga o site ao app Android (sem ele, aparece a barra do navegador) |
public/manifest.webmanifest e public/icons/ | Nome, cores e ícones do app |
twa/twa-manifest.json | Respostas de referência para o Bubblewrap |
Configurar o Firebase
Cria o servidor: contas, banco de dados e as funções do painel. Leva uns 40 minutos.
1Instale as ferramentas
Instale o Node.js 22 (LTS) e depois, no terminal:
npm install -g firebase-tools
firebase login
Baixe o projeto e instale as dependências:
git clone https://github.com/jamesrmoro/toninho-da-horta.git
cd toninho-da-horta
npm install
npm --prefix functions install2Crie o projeto no Firebase
- Abra o Console do Firebase e clique em Criar um projeto.
- Nome:
toninho-da-horta(o ID final aparece embaixo do nome, anote: é o ID do projeto). - Google Analytics: pode ativar (opcional).
3Mude para o plano Blaze
No canto de baixo à esquerda, Fazer upgrade → Blaze. Ele é obrigatório para Cloud Functions e para receber as notificações do Google Play. Um jogo pequeno costuma ficar dentro da cota grátis.
4Registre o app Web e copie as chaves
- Na página inicial do projeto, clique no ícone </> (Web), apelido "Fazendinha Retrô site". Não marque o Hosting aqui.
- Ele mostra um
firebaseConfig. Copie o arquivo de modelo e preencha com esses valores:
cp .env.example .env.production
VITE_FIREBASE_API_KEY=AIza...
VITE_FIREBASE_AUTH_DOMAIN=SEU-PROJETO.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=SEU-PROJETO
VITE_FIREBASE_APP_ID=1:123456:web:abc...
VITE_FIREBASE_STORAGE_BUCKET=SEU-PROJETO.firebasestorage.app
VITE_FIREBASE_FUNCTIONS_REGION=southamerica-east1
Esse arquivo é só da produção (usado no npm run build e no npm run deploy) e fica fora do Git. No seu computador, o jogo nunca se conecta à produção: veja a aba 3, Dev e produção.
.env?Renomeie para .env.production: mv .env .env.production5Ative os tipos de login (cadastro, login, esqueci a senha e Google)
Authentication → Começar → Método de login (Sign-in method) e ative os dois (para jogar é preciso entrar com uma conta):
- E-mail/senha: ligue só a primeira chave ("E-mail/senha"); a do "link por e-mail" pode ficar desligada. É o que faz funcionar Criar conta, Entrar com e-mail e Esqueci a senha.
- Google: ative, escolha o nome público do projeto (
Fazendinha Retrô) e o e-mail de suporte (o seu). Salve.
No jogo, ao tocar em Jogar, a pessoa entra ou cria a conta antes de começar:
- Criar conta: nome, e-mail e senha (mínimo 6). O Firebase manda um e-mail para confirmar o endereço.
- Entrar com e-mail e Esqueci a senha: o link chega por e-mail e abre uma página do próprio Firebase para criar a senha nova.
- Entrar com Google: abre a janela do Google; no app instalado, se a janela for bloqueada, entra pela própria página.
- Em cada modelo (Verificação de endereço de e-mail e Redefinição de senha), clique no lápis e troque o Nome do remetente para
Fazendinha Retrô. - Em Idioma do modelo, escolha Português (Brasil) (o jogo já pede os e-mails em português).
- Depois de ligar o domínio (aba 4), em Personalizar URL de ação use
https://jogo.fazendinharetro.com/__/auth/action, assim o link do e-mail abre no seu endereço.
Fazendinha Retrô, logo (use docs/logos/logo-quadrado-120.png, 120×120), e-mail de suporte, Página inicial https://fazendinharetro.com, Política de Privacidade https://fazendinharetro.com/privacidade, Termos de Serviço https://fazendinharetro.com/termos e, em Domínios autorizados, fazendinharetro.com.6Crie o banco de dados (Firestore)
Firestore Database → Criar banco de dados → local southamerica-east1 (São Paulo) → modo de produção. As regras certas são enviadas no passo 9.
7Ligue o projeto à pasta
firebase use --add
Escolha o seu projeto na lista e, quando ele pedir um apelido (alias), digite default. Isso cria o arquivo .firebaserc (ele fica fora do Git).
Se preferir criar o arquivo direto (troque pelo ID do seu projeto, tudo em minúsculas):
printf '{ "projects": { "default": "seu-projeto-id" } }\n' > .firebaserc8Diga quem é o superadmin
Crie o arquivo functions/.env.SEU-PROJETO (veja functions/.env.example):
SUPERADMIN_EMAILS=seu.email@gmail.com
PLAY_PACKAGE_NAME=app.toninhodahorta.twa
Quem estiver nessa lista vira superadmin no primeiro login no painel (o e-mail precisa ser verificado: use Entrar com Google). Pode ter mais de um, separados por vírgula.
9Publique tudo
npm run deploy
(É o mesmo que npm run build seguido de firebase deploy.) Isso envia o site, o painel, as regras, os índices e as funções. Na primeira vez o Firebase pode pedir para ativar algumas APIs (Cloud Build, Artifact Registry, Cloud Scheduler, Pub/Sub, Eventarc): aceite e rode de novo se der erro.
firebase login:list se está logado com a conta Proprietária do projeto e tente de novo depois de 5 minutos. Se persistir, abra o Cloud Shell (com o projeto selecionado no topo) e cole, trocando o ID na primeira linha:
PROJECT_ID=seu-projeto-id
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" --role="roles/iam.serviceAccountTokenCreator"
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" --role="roles/run.invoker"
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" --role="roles/eventarc.eventReceiver"
Depois rode npm run deploy de novo. Enquanto isso, o site, o painel e as regras já podem ir: firebase deploy --only hosting,firestore.https://SEU-PROJETO.web.appPainel:
https://SEU-PROJETO.web.app/admin/9bLiberar o seu acesso ao painel (sem Cloud Functions)
O painel fica em https://jogo.fazendinharetro.com/admin/ e só abre para quem está na lista da equipe. Sem o plano Blaze, a lista é feita à mão no Firestore:
- Firebase → Firestore Database → Iniciar coleção → ID da coleção:
admins. - ID do documento: o seu e-mail em minúsculas, exatamente como na sua conta (ex.:
voce@gmail.com). - Campo:
role, tipo string, valorsuperadmin. Salve. - Publique as regras novas (
firebase deploy --only firestore) e entre no painel com Entrar com Google usando esse e-mail. Conta de e-mail e senha também funciona, desde que o e-mail esteja confirmado.
Para tirar alguém da equipe, apague o documento dessa pessoa em admins. Os papéis possíveis são superadmin, admin e suporte (só leitura).
10Entre no painel pela primeira vez
- Abra
/admin/, clique em Entrar com Google com o e-mail do passo 8. - Na tela Usuários, abra alguém da equipe (a pessoa precisa ter entrado no jogo ou no painel uma vez) e escolha o Papel na equipe:
- Superadmin: tudo, inclusive mudar papéis.
- Administrador: banir, desbanir e configurações.
- Suporte: só visualiza.
updateStats. Para ver logo, clique em Atualizar agora no topo da Visão geral.11Cadastre os produtos à venda
No Firestore, crie a coleção products. O ID do documento é o ID do produto (igual ao do Play Console, aba 5). Campos:
| Campo | Tipo | Exemplo |
|---|---|---|
name | string | Saquinho de moedas (500) |
priceCents | number | 490 (= R$ 4,90) |
currency | string | BRL |
type | string | consumivel (pode comprar de novo) ou nao_consumivel (uma vez só) |
active | boolean | true |
12(Opcional) Teste tudo no computador, sem gastar
firebase emulators:start
Sobe Auth, Firestore, Functions e Hosting locais, com um painel em http://localhost:4000.
Dois ambientes: desenvolvimento e produção
A produção é o site publicado, com os dados reais dos jogadores. O desenvolvimento (dev) roda inteiro no seu computador, com os emuladores do Firebase: dá para testar tudo à vontade sem tocar na produção. Quando você precisar dos dados reais no dev, um superadmin autoriza no painel de produção.
| Desenvolvimento (local) | Produção | |
|---|---|---|
| Onde roda | Seu computador (emuladores) | Firebase na nuvem |
| Comandos | npm run emulators + npm run dev:full | npm run deploy |
| Configuração do site | .env.emulador (já vem pronto) | .env.production (suas chaves) |
| Configuração das funções | functions/.env.local | functions/.env.SEU-PROJETO |
| Endereços | Jogo http://localhost:5173, painel /admin/, emuladores http://127.0.0.1:4000 | https://seudominio.com.br e /admin/ |
| Selo no painel | DEV (local) | PRODUÇÃO |
npm run dev: só o jogo, salvando no aparelho (painel em modo demonstração).npm run dev:full: jogo e painel ligados aos emuladores (ambiente de dev completo).Nenhum deles conecta na produção: é proposital.
1Instale o Java (só uma vez)
O emulador do banco de dados precisa do Java 11 ou mais novo. No Windows: instale o Temurin JDK 21 e feche e abra o terminal. Para conferir:
java -version2Configure as funções locais
Na primeira vez, o npm run emulators cria o arquivo functions/.env.local. Abra e ajuste:
SUPERADMIN_EMAILS=seu.email@gmail.com
PLAY_PACKAGE_NAME=app.toninhodahorta.twa
PROD_PROJECT_ID=toni-64163
PROD_PROJECT_ID é o ID do seu projeto de produção: é de lá que a sincronização autorizada copia os dados.
3Suba o ambiente de dev (dois terminais)
Terminal 1, os emuladores (deixe aberto; Ctrl+C para sair, e os dados locais ficam salvos em .emulator-data):
npm run emulators
Terminal 2, o jogo e o painel:
npm run dev:full
Abra http://localhost:5173/admin/. O selo do topo deve mostrar DEV (local).
4Entre no painel local
Clique em Entrar com Google. No emulador aparece uma janela de teste: Add new account, digite o e-mail que está em SUPERADMIN_EMAILS e confirme. Você entra como superadmin (no dev, o e-mail não precisa ser verificado). As contas de teste aparecem em http://127.0.0.1:4000/auth.
5Na PRODUÇÃO: autorize a sincronização
- Abra o painel publicado:
https://seudominio.com.br/admin/→ Ambientes. - Escolha a validade (10, 30 ou 60 minutos) e se os dados vêm anonimizados (recomendado: nomes e e-mails são trocados, por causa da LGPD).
- Clique em Autorizar sincronização. Aparece um código como
TDH-ABCD-EFGH-JKMN-PQRS. Ele aparece só nessa hora: copie e envie com segurança.
Só o superadmin autoriza. O código funciona uma vez, expira sozinho, pode ser revogado na mesma tela e tudo fica na Auditoria da produção.
6No DEV: sincronize
- No painel local → Ambientes, cole o código.
- Deixe marcado "Apagar os dados locais antes" para o dev ficar igual à produção (suas contas de teste continuam).
- Clique em Sincronizar agora. Em seguida, na Visão geral, clique em Atualizar agora.
São copiados: perfis dos jogadores, contas (sem senhas), pedidos, produtos, configurações, estatísticas e a auditoria recente. Os tokens de compra nunca saem da produção. O progresso salvo dos jogadores só vem se você marcar essa opção ao autorizar.
7Publique quando estiver pronto
npm run deploy
Só o site: npm run deploy:site. As mudanças nas funções (functions/) e nas regras vão junto no npm run deploy.
Publicar e usar o endereço jogo.fazendinharetro.com
O site fica no Firebase Hosting, com HTTPS grátis. Primeiro ele sai no endereço do Firebase (SEU-PROJETO.web.app); depois você liga o jogo.fazendinharetro.com (um subdomínio do fazendinharetro.com; a raiz fica para a landing page, no passo 7). O domínio próprio também é o que o app Android usa.
1Baixe a versão mais nova e publique
git pull
npm install
npm run deploy
O npm run deploy monta o jogo com as chaves do .env.production e envia site, painel, regras e funções. Nas atualizações do dia a dia, basta:
npm run deploy:site
Abra https://SEU-PROJETO.web.app, toque em Entrar ou criar conta e teste: criar conta, sair, entrar com e-mail, esqueci a senha e Google.
2Onde fica o DNS do domínio
O domínio fazendinharetro.com está na GoDaddy, com o DNS da própria GoDaddy (servidores domaincontrol.com). Os registros ficam em Meus produtos → fazendinharetro.com → DNS → Registros DNS. Na GoDaddy, @ significa a raiz do domínio.
3Conecte o domínio no Firebase
- Firebase → Hosting → Adicionar domínio personalizado → digite
jogo.fazendinharetro.com→ Continuar. - Ele mostra um registro TXT (prova que o domínio é seu) e um registro A ou CNAME (endereço do servidor), todos com o nome
jogo. Deixe essa tela aberta. - Na GoDaddy: Meus produtos → fazendinharetro.com → DNS → Registros DNS → Adicionar novo registro e adicione exatamente o que o Firebase mostrou:
- Tipo TXT, nome
jogo(ou o nome que o Firebase mostrar, como_acme-challenge.jogo), valor copiado do Firebase. - Tipo A, nome
jogo, valor o IP que o Firebase mostrou (um registro A para cada IP), ou tipo CNAME, nomejogo, valorSEU-PROJETO.web.app., se for isso que ele pedir. - Na GoDaddy o campo Nome é só a parte da frente (
jogo), sem o.fazendinharetro.com.
- Tipo TXT, nome
- Volte ao Firebase e clique em Verificar. A ligação costuma sair em minutos; o certificado HTTPS pode levar até 24 horas (enquanto isso aparece "pendente").
- A raiz
fazendinharetro.com(sem ojogo) fica para a landing page, que é outro site (passo 7).
game. Na GoDaddy, apague os registros com nome game. Em Authentication → Domínios autorizados e nas credenciais do Google Cloud, troque game por jogo. Se já tinha mudado o VITE_FIREBASE_AUTH_DOMAIN, troque também.4Autorize o domínio no login
- Firebase → Authentication → Configurações → Domínios autorizados → Adicionar domínio:
jogo.fazendinharetro.com. Sem isso, o login falha no domínio novo com "domínio não autorizado". - Para o Google mostrar jogo.fazendinharetro.com na janela de login (em vez de
SEU-PROJETO.firebaseapp.com) e funcionar melhor no Safari e no app instalado, troque no.env.production:VITE_FIREBASE_AUTH_DOMAIN=jogo.fazendinharetro.com - Em Google Cloud → APIs e serviços → Credenciais, abra o Web client (auto created by Google Service) e adicione:
- Origens JavaScript autorizadas:
https://jogo.fazendinharetro.com - URIs de redirecionamento autorizados:
https://jogo.fazendinharetro.com/__/auth/handler
- Origens JavaScript autorizadas:
- Publique de novo:
npm run deploy:site.
VITE_FIREBASE_AUTH_DOMAIN depois que https://jogo.fazendinharetro.com já abrir o jogo com cadeado (HTTPS). Antes disso, deixe SEU-PROJETO.firebaseapp.com.5Confira
- Jogo:
https://jogo.fazendinharetro.com/ - Login: menu inicial → Entrar ou criar conta → criar, sair, entrar, esqueci a senha e Google.
- Contas criadas: Firebase → Authentication → Usuários; dados do jogo em Firestore → users.
- Painel:
https://jogo.fazendinharetro.com/admin/(também/painel) - Prévia ao compartilhar o link (WhatsApp, redes): imagem
/og-image.pngcom o logo. - Ligação com o Android:
https://jogo.fazendinharetro.com/.well-known/assetlinks.json(preenchido na aba 5). Otwa/twa-manifest.jsonjá aponta parajogo.fazendinharetro.com. - Guia:
https://jogo.fazendinharetro.com/guia.html
6(Recomendado) Proteções extras
- Authentication → Configurações → Proteção contra enumeração de e-mail: deixe ligada (o "Esqueci a senha" não revela se o e-mail tem conta).
- App Check (Firebase → App Check, com reCAPTCHA Enterprise no site e Play Integrity no Android) bloqueia chamadas que não venham do seu app.
- Equipe: use contas Google com verificação em duas etapas.
- Cada ação do painel fica na Auditoria; ninguém apaga pelo painel.
7Landing page no fazendinharetro.com (segundo site)
A página de apresentação fica na pasta landing/ e vai para um segundo site do mesmo projeto. O jogo continua em jogo.fazendinharetro.com; a landing fica em fazendinharetro.com.
Uma vez só, crie o site e dê nome aos dois (troque SEU-PROJETO-ID; se fazendinharetro estiver ocupado, use outro ID, como fazendinharetro-site):
firebase hosting:sites:create fazendinharetro
firebase target:apply hosting game SEU-PROJETO-ID
firebase target:apply hosting landing fazendinharetro
Depois disso: npm run deploy:site publica só o jogo, npm run deploy:landing só a landing e npm run deploy tudo.
npm run deploy:landing
- Firebase → Hosting → site fazendinharetro → Adicionar domínio personalizado →
fazendinharetro.com(deixe "Redirecionar" desmarcado). - Na GoDaddy, cadastre com o nome
@(a raiz) o TXT e o registro A que o Firebase mostrar, e apague qualquer outro A/AAAA com nome@. Se o Firebase pedir para remover o15.197.148.33e ele não estiver na lista, é a página estacionada antiga ainda em cache: espere uma ou duas horas e clique em Verificar de novo. - (Opcional)
www.fazendinharetro.comno mesmo site, com Redirecionar para fazendinharetro.com.
geracao-de-imagens/landing/ com o nome do cartão (ex.: lp_hero_sky.png), rode npm run landing:imagens e npm run deploy:landing: a página troca a arte sozinha.Publicar na Google Play (TWA) com Google Play Billing
O app Android é um TWA: abre o site do seu domínio em tela cheia, sem barra do navegador. Os pagamentos usam o Google Play Billing pela Digital Goods API, já preparada em src/services/billing.ts.
1Crie a conta no Play Console
play.google.com/console, taxa única de US$ 25 e verificação de identidade. Crie também o perfil de pagamentos (para vender e receber).
2Instale o Bubblewrap
npm install -g @bubblewrap/cli
bubblewrap doctor
Na primeira execução ele oferece baixar o JDK 17 e o Android SDK: responda sim.
3Gere o projeto Android
Com o site já publicado no seu domínio (aba 4):
mkdir -p twa/app && cd twa/app
bubblewrap init --manifest https://seudominio.com.br/manifest.webmanifest
Respostas (as mesmas de twa/twa-manifest.json):
| Pergunta | Resposta |
|---|---|
| Domain | seudominio.com.br |
| URL path | /?source=twa (é assim que o jogo sabe que está no Android) |
| Application ID | app.toninhodahorta.twa (igual ao PLAY_PACKAGE_NAME; não dá para mudar depois) |
| Display mode | fullscreen |
| Include support for Play Billing? | Yes |
| Key store | deixe criar uma nova e guarde o arquivo e as senhas fora do Git (sem elas você não atualiza o app nunca mais) |
4Compile
bubblewrap build
Gera app-release-bundle.aab (vai para a loja) e app-release-signed.apk (para instalar no seu celular e testar).
5Crie o app e envie para teste interno
- Play Console → Criar app → nome, idioma Português (Brasil), Jogo, Gratuito.
- Testar e lançar → Teste interno → Criar versão → envie o
.aab. Aceite o Play App Signing. - Adicione o seu e-mail como testador e instale pelo link de teste.
6Ligue o site ao app (assetlinks)
- Play Console → Configuração → Integridade do app → Assinatura de apps: copie a impressão digital SHA-256 da chave de assinatura do app (e, para testar o APK local, também a da chave de upload).
- Cole em
public/.well-known/assetlinks.json:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "app.toninhodahorta.twa",
"sha256_cert_fingerprints": [
"AA:BB:...:CHAVE-DE-ASSINATURA-DO-PLAY",
"11:22:...:CHAVE-DE-UPLOAD"
]
}
}]
npm run build
firebase deploy --only hosting
Se o app abrir com uma barrinha de endereço no topo, o assetlinks está errado ou ainda não foi publicado (feche e abra o app depois de corrigir).
7Crie os produtos no Play Console
Monetizar → Produtos → Produtos no app → Criar produto. O ID precisa ser exatamente o mesmo do documento em products/ do Firestore (aba 2, passo 11). Defina o preço e Ative.
Assinaturas ficam em Monetizar → Produtos → Assinaturas (a verificação de assinaturas ainda precisa de uma função própria; os produtos avulsos já estão prontos).
8Dê ao servidor acesso aos pedidos
- No Google Cloud do mesmo projeto, ative a Google Play Android Developer API.
- Descubra a conta de serviço das funções: em IAM e administrador → Contas de serviço, é a
NUMERO-compute@developer.gserviceaccount.com(conta padrão do Compute, usada pelas Functions de 2ª geração). - No Play Console: Usuários e permissões → Convidar novos usuários → cole esse e-mail → em Permissões do app escolha o seu app → marque Ver dados financeiros e Gerenciar pedidos e assinaturas → Convidar.
9Receba reembolsos e cancelamentos automaticamente
- O deploy já criou a função
playRtdn, que escuta o tópico do Pub/Subplay-billing. Confira em Pub/Sub → Tópicos (crie com esse nome se não existir). - No tópico
play-billing: Permissões → Adicionar principal →google-play-developer-notifications@system.gserviceaccount.com→ papel Publicador do Pub/Sub. - Play Console → Monetizar → Configuração de monetização → Notificações do desenvolvedor em tempo real → tópico
projects/SEU-PROJETO/topics/play-billing→ Enviar mensagem de teste. - Veja nos logs:
firebase functions:log --only playRtdndeve mostrar "Notificação de teste do Google Play recebida".
10Compre de teste sem pagar
Play Console → Configuração → Teste de licença → adicione os e-mails da equipe. Esses e-mails compram com cartões de teste, e os pedidos aparecem no painel com a etiqueta teste (fora da receita).
11Como o jogo vende (para o desenvolvedor)
O fluxo já está pronto. Quando a loja de dinheiro real for criada no jogo, basta usar:
import { billingAvailable, buy, getPrices, restorePurchases } from './services/billing';
import { services } from './services';
const verify = (id: string, token: string) => services().verifyPurchase(id, token);
if (await billingAvailable()) { // só no app Android
const prices = await getPrices(['moedas_pequeno']); // preço na moeda do jogador
const r = await buy('moedas_pequeno', verify); // abre a tela do Google
if (r.ok) { /* o item foi liberado em users/{uid}/grants/{orderId} */ }
}
await restorePurchases(verify); // ao abrir o jogo
Caminho de uma compra: tela do Google → token → função verifyPlayPurchase confere com o Google, grava em orders/, libera em users/{uid}/grants/ e confirma (consome ou reconhece) a compra. Sem confirmação, o Google devolve o dinheiro em 3 dias.
12Ficha da loja e lançamento
- Ficha da loja principal: ícone 512×512, imagem de destaque 1024×500 e capturas de tela (a página de prompts gera esses itens).
- Política de privacidade (URL pública), classificação de conteúdo, público-alvo e segurança dos dados (conta Google/anônima, compras).
- Promova a versão: teste interno → teste fechado → produção.
13Atualizações do app Android
Mudou só o jogo? firebase deploy --only hosting e pronto. Só gere um novo .aab quando mudar nome, ícone, cores ou o pacote: aumente appVersionCode em twa-manifest.json e rode bubblewrap update e depois bubblewrap build. Para obrigar os jogadores a atualizar, use Versão mínima nas Configurações do painel.
iPhone (iOS)
O TWA é uma tecnologia do Android e não existe no iPhone. Existem dois caminhos.
A) Atalho na tela inicial (grátis, hoje)
No Safari: abra o jogo → Compartilhar → Adicionar à Tela de Início. Abre em tela cheia, com o ícone do jogo, já está pronto neste projeto. Não fica na App Store e não tem compras dentro do app.B) App na App Store (Capacitor)
Empacota o mesmo site num app nativo. Precisa de Mac com Xcode e do Apple Developer Program (US$ 99/ano). Compras obrigatoriamente pela Apple (StoreKit).1Crie o app iOS com Capacitor (no Mac)
npm install @capacitor/core @capacitor/ios
npm install -D @capacitor/cli
npx cap init "Fazendinha Retrô" app.toninhodahorta.ios --web-dir dist
npm run build
npx cap add ios
npx cap sync ios
npx cap open ios
No Xcode: escolha o seu time (Signing & Capabilities), adicione a capacidade In-App Purchase e rode no iPhone. O jogo detecta sozinho que está no iPhone (src/services/platform.ts).
2Compras pela Apple
- Crie os produtos no App Store Connect → Compras dentro do app, de preferência com os mesmos IDs.
- Use um plugin de compras para Capacitor (por exemplo, RevenueCat ou
cordova-plugin-purchase). - Valide no servidor com a App Store Server API: será preciso uma função
verifyAppStorePurchase, no mesmo modelo daverifyPlayPurchase(ainda não incluída). - No iPhone,
billing.tsresponde "indisponível" de propósito: o Google Play Billing não funciona lá.
3Regras da Apple que mais reprovam
- Se o app oferece login com Google, a Apple pede também uma opção equivalente com privacidade (na prática, Entrar com a Apple). O jogador anônimo continua funcionando.
- O app precisa parecer um app: tela cheia, funcionar offline o básico (já tem service worker) e não depender de links externos.
- Nenhum outro meio de pagamento para itens digitais.
- Permita apagar a conta pelo próprio app.
Checklist final
Site
Abre em https://jogo.fazendinharetro.com com HTTPS; criar conta, entrar com e-mail, esqueci a senha e Google funcionam; o progresso aparece em users/ no Firestore.
Painel
Você entra como superadmin; a Visão geral mostra números; banir e desbanir funciona; aparece na Auditoria.
Android
O app abre sem barra de endereço; uma compra de teste aparece em Pedidos com a etiqueta "teste"; um reembolso de teste vira "Reembolsado".
Segurança
Keystore e senhas guardadas em dois lugares seguros; alerta de orçamento criado; equipe com verificação em duas etapas.
Problemas comuns
| Sintoma | Causa e solução |
|---|---|
Invalid project id em qualquer comando firebase | O arquivo .firebaserc tem um ID inválido (com maiúsculas ou texto de exemplo). Apague-o (rm .firebaserc) e rode firebase use --add. |
| Painel diz "Esta conta não tem permissão" | O e-mail não está em SUPERADMIN_EMAILS, o login não foi pelo Google (e-mail não verificado) ou faltou firebase deploy --only functions depois de mudar o arquivo. |
| Painel em "modo demonstração" no site publicado | O .env.production não existia na hora do npm run build. Preencha e publique de novo. |
| No computador, o jogo não conecta no Firebase | É de propósito: o npm run dev nunca usa a produção. Use npm run emulators e npm run dev:full (aba 3). |
| Sincronização: "Código não encontrado" ou "já foi usado" | Cada código vale uma vez e por poucos minutos. Gere outro no painel de PRODUÇÃO, aba Ambientes. Confira também o PROD_PROJECT_ID em functions/.env.local. |
| "Ainda não há estatísticas" | Clique em Atualizar agora na Visão geral (no dev é sempre necessário: lá as rotinas agendadas não rodam sozinhas). |
Deploy: We failed to modify the IAM policy for the project | Primeiro deploy das funções. (1) Confira se está logado com a conta dona do projeto: firebase login:list (troque com firebase logout e firebase login). (2) Espere 5 minutos e rode npm run deploy de novo. (3) Se continuar, dê as permissões pelo Cloud Shell (passo 9 da aba 2, quadro "Se der erro de IAM"). |
| Erro pedindo índice no painel | Rode firebase deploy --only firestore:indexes e espere alguns minutos. |
| App Android com barra do navegador | SHA-256 errado ou ausente no assetlinks.json, ou o pacote diferente. Confira o arquivo no endereço /.well-known/assetlinks.json. |
| Compra: "sem permissão" na verificação | A conta de serviço ainda não foi convidada no Play Console ou faltam até 24 h para a permissão valer (aba 5, passo 8). |
| Compra: "Produto não cadastrado" | Falta o documento em products/ com o mesmo ID do Play Console. |
| Billing indisponível no celular | O app foi gerado sem "Play Billing" no Bubblewrap ou o celular foi aberto pelo navegador, não pelo app. |