Compra no App (IAP) na Unity: Configurar do Zero

Unity in app purchase do zero com IAP 5: catálogo consumível e não consumível, código C# de compra e restauração, produto no Play Console e teste.
Compra no App (IAP) na Unity: Configurar do Zero
Para fazer unity in app purchase hoje você usa o pacote Unity IAP 5 (com.unity.purchasing), que no Unity 6.3 LTS está na versão 5.4.4. O fluxo é: instalar o pacote, declarar os produtos com o mesmo ID que você cria no Google Play Console, conectar o StoreController, comprar, entregar o item e confirmar a compra. O teste acontece com uma conta de testador de licença, sem cobrança.
O motivo deste post existir: a versão 5 do pacote mudou a API inteira, e boa parte dos tutoriais ainda mostra IStoreListener e UnityPurchasing.Initialize, que pertencem à linha 4. Aqui o código é da API atual, do zero até uma compra de teste aprovada.
Tipos de produto: consumível, não consumível, recorrente
Antes do código, decida o que você vende. O tipo muda como a compra é entregue e restaurada.
- Consumível (
ProductType.Consumable): pode ser comprado várias vezes. Moedas, vidas, pacote de energia. A loja não guarda histórico para você restaurar: quem guarda o saldo é o seu jogo (save local ou servidor). - Não consumível (
ProductType.NonConsumable): compra única e permanente. Remover anúncios, desbloquear o jogo completo, uma skin. A loja lembra, e o jogador recupera ao reinstalar. - Recorrente (
ProductType.Subscription): cobrança periódica, como passe VIP mensal. Exige tratar renovação, cancelamento e período de carência. Para um primeiro jogo, deixe de fora.
Para um jogo indie, a combinação que mais funciona é um não consumível "remover anúncios" e dois ou três pacotes consumíveis. Se você ainda está decidindo o modelo de receita, o post sobre modelos de monetização de jogos ajuda a escolher antes de programar.
Instalar e configurar o Unity IAP
- Abra Window > Package Management > Package Manager, procure In-App Purchasing no Unity Registry e instale. Confira se a versão é 5.x.
- Em File > Build Profiles, deixe Android como plataforma ativa.
- Abra Project Settings > Services > In-App Purchasing e confirme que o serviço está ligado. Em Google Play Configuration, cole a chave pública de licença do seu app (Play Console > Monetizar com o Google Play > Configuração da monetização). Ela é usada para conferir localmente se o recibo veio mesmo do Google.
- Gere um AAB e envie para a faixa de teste interno. O Play Console só libera a criação de produtos no app depois que recebe um build que contém a biblioteca de faturamento.
O pacote 5.4 já traz a Google Play Billing Library 9.0.0 (segundo o changelog do pacote). Isso importa porque a Google exige Billing Library 8 ou superior para apps novos e atualizações desde 31/08/2026, conforme a página de descontinuação da Billing Library no Android Developers. Pacote IAP antigo é motivo de rejeição de atualização.
Unity IAP: catálogo de produtos
O catálogo é a lista de produtos que o jogo conhece. Use IDs em minúsculas, sem espaço, no formato nomedojogo.item. O mesmo ID vai no Play Console, letra por letra.
Para manter IDs num lugar só, crie uma classe estática. Arquivo ProductIds.cs:
public static class ProductIds
{
public const string Coins100 = "meujogo.moedas100";
public const string Coins500 = "meujogo.moedas500";
public const string RemoveAds = "meujogo.removeranuncios";
}
Constante evita o erro mais bobo e mais comum de IAP: digitar o ID diferente em dois lugares.
Unity in app purchase: código de compra em C#
O StoreController da IAP 5 trabalha com eventos. A regra mais importante da documentação: assine todos os eventos antes de chamar Connect(), porque compras pendentes de uma sessão anterior podem chegar logo na reconexão.
O fluxo de compra tem duas etapas. O jogador compra, a loja aprova e você recebe um PendingOrder em OnPurchasePending. Você entrega o item e chama ConfirmPurchase. Se o jogo fechar entre a aprovação e a confirmação, a compra pendente volta na próxima abertura, e o jogador não perde nada.
Arquivo IapManager.cs:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
public class IapManager : MonoBehaviour
{
[SerializeField] private PlayerWallet wallet;
private StoreController store;
private bool productsReady;
private async void Awake()
{
store = UnityIAPServices.StoreController();
store.OnPurchasePending += HandlePurchasePending;
store.OnPurchaseConfirmed += HandlePurchaseConfirmed;
store.OnPurchaseFailed += HandlePurchaseFailed;
store.OnPurchaseDeferred += HandlePurchaseDeferred;
store.OnStoreConnected += HandleStoreConnected;
store.OnStoreDisconnected += failure => Debug.LogError("Loja desconectada: " + failure.Message);
store.OnProductsFetched += HandleProductsFetched;
store.OnProductsFetchFailed += failure => Debug.LogError("Falha ao buscar produtos: " + failure.FailureReason);
store.OnPurchasesFetched += HandlePurchasesFetched;
await store.Connect();
}
private void HandleStoreConnected()
{
List<ProductDefinition> catalog = new List<ProductDefinition>
{
new ProductDefinition(ProductIds.Coins100, ProductType.Consumable),
new ProductDefinition(ProductIds.Coins500, ProductType.Consumable),
new ProductDefinition(ProductIds.RemoveAds, ProductType.NonConsumable)
};
store.FetchProducts(catalog);
}
private void HandleProductsFetched(List<Product> products)
{
productsReady = true;
// Compras só podem ser buscadas para produtos que a loja já devolveu.
store.FetchPurchases();
}
public void Buy(string productId)
{
if (!productsReady)
{
Debug.LogWarning("Produtos ainda não carregaram.");
return;
}
store.PurchaseProduct(productId);
}
public string GetPrice(string productId)
{
Product product = store.GetProductById(productId);
return product != null ? product.metadata.localizedPriceString : "";
}
private void HandlePurchasePending(PendingOrder order)
{
Product product = order.CartOrdered.Items().FirstOrDefault()?.Product;
if (product == null)
{
return;
}
Grant(product.definition.id);
store.ConfirmPurchase(order);
}
private void HandlePurchaseConfirmed(Order order)
{
if (order is FailedOrder failed)
{
Debug.LogError("Confirmação falhou: " + failed.FailureReason);
}
}
private void HandlePurchaseFailed(FailedOrder failed)
{
Debug.LogWarning("Compra falhou: " + failed.FailureReason + " " + failed.Details);
}
private void HandlePurchaseDeferred(DeferredOrder deferred)
{
Debug.Log("Compra aguardando pagamento ou aprovação.");
}
private void HandlePurchasesFetched(Orders orders)
{
foreach (ConfirmedOrder confirmed in orders.ConfirmedOrders)
{
Product product = confirmed.CartOrdered.Items().FirstOrDefault()?.Product;
if (product != null && product.definition.type == ProductType.NonConsumable)
{
Grant(product.definition.id);
}
}
}
private void Grant(string productId)
{
switch (productId)
{
case ProductIds.Coins100: wallet.AddCoins(100); break;
case ProductIds.Coins500: wallet.AddCoins(500); break;
case ProductIds.RemoveAds: wallet.SetAdsRemoved(true); break;
}
}
}
O PlayerWallet é o seu sistema de save: um componente com AddCoins(int amount) e SetAdsRemoved(bool value) que grava em disco na hora. Gravar imediatamente importa: se você só salva ao sair da fase e o jogo fecha, a moeda comprada some.
Nos botões da loja, chame Buy(ProductIds.Coins100) e mostre o preço com GetPrice. O preço vem da loja já em reais e formatado, então nunca escreva preço fixo no texto do botão.
Restaurar compras e validar recibo
No Android, FetchPurchases(), chamado depois que os produtos chegam, já devolve as compras confirmadas da conta Google do aparelho, e o HandlePurchasesFetched reaplica os não consumíveis. Reinstalou, abriu, o "remover anúncios" volta sozinho.
No iOS, a Apple exige um botão de restaurar compras visível. Ele chama store.RestoreTransactions(callback), e cada compra restaurada passa de novo por OnPurchasePending. Como Grant de um não consumível é idempotente (ligar algo que já está ligado), entregar duas vezes não causa dano. Para consumível, a restauração não se aplica.
Sobre validação: a checagem local de recibo com a chave pública barra o golpe mais simples, mas um aparelho modificado pode enganar o próprio jogo. Se a compra dá vantagem em ranking ou multiplayer, valide no servidor consultando a API de desenvolvedor do Google Play antes de entregar. O post sobre compras no app em jogos explica a lógica de validação e o design dos produtos, independente da engine.
Neste ponto você tem loja, catálogo e compra funcionando. O que costuma travar quem faz sozinho vem depois: integrar a moeda comprada com a economia do jogo, salvar sem perder progresso, montar a UI da loja e equilibrar tudo para a compra parecer justa. É o tipo de costura entre sistemas que um projeto guiado resolve melhor do que tentativa e erro.
Criar o produto no Google Play Console
Com o build no teste interno:
- No Play Console, abra o app e vá em Monetizar com o Google Play > Produtos > Produtos no app.
- Clique em Criar produto. O ID do produto é o mesmo da constante (
meujogo.moedas100). Ele não pode ser alterado nem reaproveitado depois. - Preencha nome e descrição (aparecem na tela de compra do Google).
- Defina o preço em reais. O Console sugere conversão para outros países; revise os principais.
- Salve e clique em Ativar. Produto inativo não aparece para ninguém.
Quanto à taxa, a página de taxas de serviço da central de ajuda do Play Console, consultada em outubro de 2026, lista para os mercados que ainda seguem a estrutura anterior (o que inclui o Brasil na data da consulta) 15% sobre o primeiro US$ 1 milhão de receita por ano e 30% acima disso em transações comuns, e 15% em produtos recorrentes. A própria página informa que uma estrutura nova já vale em alguns mercados e será expandida, então confira antes de precificar.
Testar com license testers
- Em Configuração > Teste de licença (na página inicial do Play Console, fora do app), adicione os e-mails das contas Google que vão testar.
- Adicione as mesmas contas como testadoras da faixa de teste interno do app.
- No celular, logado com essa conta, abra o link de participação e instale o jogo pela Play Store. Instalação por cabo não conversa com o faturamento do jeito certo.
- Compre. A tela do Google mostra métodos de teste ("cartão de teste, sempre aprovado", "sempre recusado", entre outros). Teste os dois caminhos.
Teste também: fechar o app no meio da compra e reabrir (a pendência tem que ser entregue), comprar sem internet, e reinstalar para ver o não consumível voltar.
Erros comuns: produto não encontrado, compra pendente
- Produto não aparece /
GetProductByIdvolta nulo: ID divergente, produto não ativado, conta do aparelho fora da lista de testadores ou app instalado fora da faixa de teste. Também acontece nas primeiras horas depois de criar o produto. - Compra pendente que nunca conclui: com método de pagamento que demora a compensar, a loja entrega
OnPurchaseDeferred. Não entregue o item ainda: ele chega porOnPurchasePendingquando o pagamento compensar. - Item entregue duas vezes: você entregou em
OnPurchasePendinge de novo em outro lugar. Centralize emGrant. - Item comprado e não entregue: esqueceu de chamar
ConfirmPurchase, e o Google reembolsa compras não confirmadas depois de alguns dias. - Código de tutorial antigo não compila:
IStoreListener,ConfigurationBuildereProcessPurchasesão da IAP 4. Use a API doStoreController. - Erro no editor: no Play Mode a IAP usa uma loja falsa para teste rápido. Ela não valida ID nem preço reais, então a validação de verdade é sempre no aparelho.
Próximo passo
Implemente só o "remover anúncios" primeiro: um produto, não consumível, testável em uma tarde. Quando ele estiver comprando, restaurando e sobrevivendo a reinstalação, acrescente os consumíveis. Para o caminho completo do build até a loja, veja como publicar jogo Unity na Play Store.
Perguntas frequentes
Qual versão do Unity IAP usar no Unity 6.3?
A página do pacote no manual do Unity 6.3 lista o com.unity.purchasing 5.4.4. A linha 5 trocou a API antiga (IStoreListener e UnityPurchasing.Initialize) pelo StoreController, então tutoriais anteriores a 2025 não compilam sem adaptação.
Unity IAP funciona com a Google Play Billing exigida em 2026?
Sim. O changelog do pacote mostra que a versão 5.4.0 atualizou a Google Play Billing Library para a 9.0.0. A Google exige Billing Library 8 ou superior em apps novos e atualizações desde 31/08/2026, então qualquer 5.4.x atende.
Por que meu produto IAP não aparece no jogo?
As causas mais comuns são ID diferente entre o código e o Play Console, produto inativo, app instalado fora de uma faixa de teste, ou conta do celular que não é testadora. Também é preciso ter enviado ao menos um build com a biblioteca de faturamento para o Console liberar a criação de produtos.
Como testar compra no app sem pagar?
Cadastre seu e-mail como testador de licença no Play Console e instale o jogo por uma faixa de teste (interno ou fechado). Na hora da compra aparecem cartões de teste que aprovam ou recusam sem cobrança real.


