1. Introdução
Este codelab ensina a usar a Biblioteca Google Play Faturamento (PBL, na sigla em inglês) para gerenciar mudanças no plano de assinatura. Você vai descobrir como vários modos de substituição afetam os preços e os direitos de acesso dos usuários enquanto aprende a processar Notificações do Desenvolvedor em Tempo Real (RTDNs) de back-end.
Público
Criado para desenvolvedores de apps Android, este codelab oferece orientações sobre a implementação de recursos sofisticados de gerenciamento de assinaturas. As orientações ajudam você a oferecer aos usuários uma experiência perfeita para fazer upgrade, downgrade ou transição entre diferentes planos de assinatura.
O que você vai aprender…
- Como criar assinaturas no Play Console.
- Como escolher o
ReplacementModecorreto (por exemplo,WITH_TIME_PRORATIONxDEFERRED) para corresponder às políticas de upgrade e downgrade do seu app. - Como configurar
BillingFlowParamsemlaunchBillingFlowpara acionar o fluxo de compra do Google Play para uma substituição de plano. - Como usar as notificações do desenvolvedor em tempo real (RTDN) e a API
purchases.subscriptionsv2para revogar com segurança o acesso antigo e conceder um novo acesso no seu back-end
O que é necessário
- Acesso ao Google Play Console com uma conta de desenvolvedor. Se você não tiver uma conta de desenvolvedor, crie uma.
- O app de exemplo deste codelab, que pode ser baixado do GitHub.
- Android Studio
2. Criar o app de amostra
Este codelab usa um app Android de exemplo para mostrar como implementar substituições de assinaturas na PBL. O app de exemplo foi projetado para ser um app Android totalmente funcional com o código-fonte completo que mostra os seguintes aspectos:
- Integrar o app com a PBL
- Implementar substituições de assinatura
Se você já conhece as substituições de assinaturas e o PBL, baixe o app de exemplo e teste.
O vídeo de demonstração a seguir mostra como o app de exemplo vai aparecer e se comportar depois de implantado e executado.
Pré-requisitos
Antes de criar e implantar o app de exemplo, faça o seguinte:
- Crie uma conta de desenvolvedor do Google Play Console. Se você já tiver uma conta de desenvolvedor, pule esta etapa.
- Crie um app no Play Console com os recursos de monetização ativados. Como alternativa, use um app já existente no Play Console. Se os recursos de monetização não estiverem ativados no seu app, siga estas etapas para configurar.
- Instale o Android Studio.
Criar
Para criar o app de exemplo conforme necessário para seguir o codelab:
- Faça o download do app de exemplo no GitHub.
- Atualize o
applicationIdnobuild.gradledo app de exemplo para refletir o ID do aplicativo no Play Console. - Crie o app de exemplo.
Observação: isso cria o app para testes locais. No entanto, a execução do app não busca produtos e preços porque as assinaturas necessárias ainda não foram criadas no Play Console. A próxima seção vai abordar a criação de assinaturas no Developer Console.
3. Criar assinaturas no Play Console
O sistema de assinaturas do Google Play oferece flexibilidade para criar, gerenciar e vender assinaturas. No Play Console, é possível configurar assinaturas com vários planos básicos, cada um com várias ofertas. As ofertas de assinatura podem ter vários modelos de preços e opções de qualificação. Neste codelab, você vai criar três assinaturas: Plano Premium, Plano básico e Plano Lite, simulando uma oferta de assinatura típica em vários preços. Cada uma delas terá um único plano básico mensal recorrente.
Criar uma nova assinatura
Para criar uma assinatura
- Abra o Play Console e acesse a página "Assinaturas" (Monetizar com o Google Play > Produtos > Assinaturas).
- Clique em Criar assinatura.
- Insira os detalhes da assinatura:
- ProductID : insira um ID de produto exclusivo. Insira
premium_plan. - Nome : insira um nome curto para a assinatura. Exemplo:
Premium Plan.
- ProductID : insira um ID de produto exclusivo. Insira
- Clique em Criar.
Criar o Base Plan
- Abra o Play Console e acesse a página "Assinaturas" (Monetizar com o Google Play > Produtos > Assinaturas).
- Ao lado da assinatura em que você quer criar um plano básico, clique na seta para a direita para conferir os detalhes.
- Clique em Adicionar plano básico.
- Insira um ID do plano básico. Por exemplo,
monthly-auto-renewing. - Escolha o tipo Renovação automática.
- Para o plano básico com renovação automática, defina o seguinte:
- Período de faturamento: mensal.
- Período de carência: 7 dias.
- Mudanças no plano de faturamento e na oferta: Cobrar na data de faturamento.
- Renovar a assinatura: Permitir.
- Na seção Preço e disponibilidade, clique em Definir preços para definir o preço do plano básico.
- Selecione todos os países e regiões e clique em Definir preço.
- Defina o preço como US$10 para esse plano básico e clique em Atualizar.
- Depois de definir o preço do plano básico, clique em Salvar e em Ativar no canto inferior direito.
Criar assinaturas para o app de exemplo
Para este codelab, crie mais duas assinaturas com a seguinte configuração:
- Plano básico
- ID do produto: basic_plan
- Nome: Plano básico
- ID do plano básico: monthly-auto-renewing
- Preço: R$5
- Plano Lite
- ID do produto: lite_plan
- Nome: Plano Lite
- ID do plano básico: monthly-auto-renewing
- Preço: US$3
O app de exemplo está configurado para usar esses IDs de produto e de plano básico. É possível criar assinaturas diferentes com configurações diferentes. Nesse caso, você terá que modificar o app de exemplo para usar o ID do produto criado.
Vídeo sobre como criar uma assinatura
O vídeo a seguir mostra as etapas descritas anteriormente para criar uma assinatura no Play Console para desenvolvedores.
4. Substituições de assinatura
Os desenvolvedores que integram com a PBL podem oferecer aos assinantes várias opções para mudar o plano de assinatura e atender melhor às necessidades deles:
- Se você vende diversos níveis de assinatura, como básica e premium, permita que os usuários mudem de nível comprando o plano básico ou uma oferta de assinatura diferente.
- Você pode permitir que os usuários mudem o período de faturamento atual, por exemplo, passando do plano mensal para o anual.
- Também é possível permitir que eles alternem entre os planos pré-pago e com renovação automática.
Quando os usuários decidem fazer upgrade, downgrade ou mudar a assinatura, você especifica um modo de substituição que determina como o valor proporcional do período de faturamento atual é aplicado e quando a mudança de direito de acesso ocorre para os usuários.
A Play Billing Library oferece várias opções de ReplacementMode para controlar esse comportamento.
Modos de substituição disponíveis
WITH_TIME_PRORATION: o item da assinatura recebe upgrade ou downgrade imediatamente. Qualquer tempo restante é ajustado com base na diferença de preço e creditado à nova assinatura, atualizando a próxima data de faturamento. Esse é o comportamento padrão.CHARGE_PRORATED_PRICE: o item da assinatura recebe upgrade imediatamente, e o ciclo de faturamento permanece o mesmo. A diferença de preço referente ao período restante é cobrada do usuário.CHARGE_FULL_PRICE: o item de assinatura recebe upgrade ou downgrade imediatamente, e o usuário recebe a cobrança imediata do preço total pelo novo direito de acesso. O valor restante da assinatura anterior é transferido para o mesmo direito de acesso ou um valor proporcional ao tempo é transferido ao mudar para outro.WITHOUT_PRORATION: o item de assinatura recebe upgrade ou downgrade imediatamente, e o novo preço é cobrado quando a assinatura é renovada. O ciclo de faturamento permanece o mesmo.DEFERRED: o item da assinatura só recebe upgrade ou downgrade quando ela é renovada.
5. WITH_TIME_PRORATION
Nesse modo, o item da assinatura é atualizado ou recebe um downgrade imediatamente. Qualquer tempo restante é ajustado com base na diferença de preço e creditado à nova assinatura, adiando a próxima data de faturamento. Esse é o comportamento padrão.
Exemplo de cenário
Um usuário muda de um plano Basic (US$ 4,99 por mês) para um plano Premium (US$ 9,99 por mês) em 15 de abril, que é a metade do ciclo de faturamento mensal.
Nesse caso:
- O usuário recebe acesso ao plano Premium imediatamente.
- O Google Play calcula automaticamente o período proporcional. Por exemplo, se o Google Play calcular que os 15 dias restantes do plano Basic valem 7 dias do plano Premium, a próxima data de faturamento será antecipada para 21 de abril.
- O usuário não precisa fazer um pagamento imediato.
Snippet de código
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Fazer upgrade com WITH_TIME_PRORATION
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Premium.
O direito do usuário é atualizado para o plano Premium imediatamente. O valor a ser pago imediatamente pelo usuário é de US $0,00. O valor restante do plano Basic é proporcional ao tempo do plano Premium, o que antecipa a próxima data de renovação. O usuário vai receber uma cobrança de US $9,99 na nova data de faturamento ajustada.
Fazer downgrade com WITH_TIME_PRORATION
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Lite.
O direito do usuário é rebaixado imediatamente para o plano Lite. O valor a ser pago imediatamente é de US $0,00. O valor restante do plano Basic é proporcional ao tempo do plano Lite, o que estende significativamente a próxima data de renovação. O usuário vai receber uma cobrança de US $2,99 na nova data de faturamento ajustada.
Conclusão
Nesta seção, você aprendeu como o WITH_TIME_PRORATION modifica os direitos do usuário sem cobranças imediatas, ajustando o tempo até a próxima renovação com base na diferença de preço. É uma estratégia padrão eficaz para fazer upgrade ou downgrade de usuários.
6. CHARGE_PRORATED_PRICE
Nesse modo de substituição, o item da assinatura recebe upgrade imediatamente, e o ciclo de faturamento permanece o mesmo. A diferença de preço referente ao período restante é cobrada do usuário.
Observação: essa opção está disponível apenas para um upgrade de item de assinatura, em que o preço por unidade de tempo aumenta.
Exemplo de cenário
Um usuário do plano Básico (R$ 7,99 por mês) decide fazer upgrade para o plano Premium (R$ 39,99 por mês) em 20 de abril, faltando cerca de 10 dias para o fim do ciclo de faturamento mensal.
Nesse caso:
- O usuário recebe acesso ao plano Premium imediatamente.
- O usuário recebe imediatamente a cobrança proporcional da diferença pelos 10 dias restantes do ciclo de faturamento atual. Isso equivale a aproximadamente US $2,99, representando 10 dias do plano Premium.
- A data de faturamento do usuário não muda.
Snippet de código
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Fazer upgrade com CHARGE_PRORATED_PRICE
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Premium.
O usuário recebe um upgrade imediato para o plano Premium, mantendo a data de renovação original. O valor a ser pago imediatamente é a diferença proporcional entre os preços dos planos Premium e Basic pelos dias restantes do ciclo atual. Na data de renovação, o valor total da renovação do Premium (US $9,99) será cobrado do usuário.
Fazer downgrade com CHARGE_PRORATED_PRICE
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Lite.
Esse modo de substituição resulta em um erro durante um downgrade porque está disponível apenas para upgrades de itens de assinatura em que o preço por unidade de tempo aumenta. O fluxo de faturamento vai falhar e mostrar um erro ao usuário informando que o modo de cálculo proporcional é indisponível para downgrades.
Conclusão
Esta seção explicou como o CHARGE_PRORATED_PRICE permite upgrades imediatos cobrando dos usuários a diferença exata de preço pelo período de faturamento restante, mantendo o ciclo de faturamento intacto. Isso é útil quando os usuários querem fazer upgrade para um nível mais caro sem mudar a data de faturamento.
7. CHARGE_FULL_PRICE
Nesse modo de substituição, o item de assinatura recebe upgrade ou downgrade imediatamente, e o usuário recebe a cobrança imediata do preço total pelo novo direito de acesso. O valor restante da assinatura anterior é transferido para o mesmo direito de acesso ou um valor proporcional ao tempo é transferido ao mudar para outro.
Exemplo de cenário
Um usuário tem o plano Basic (US$ 4,99 por mês a partir de 1º de abril). Em 20 de abril, o usuário quer mudar para o plano Premium (US$ 9,99 por mês).
Nesse caso:
- O usuário recebe imediatamente a cobrança do preço total do plano Premium (US$ 9,99).
- O valor restante do plano Basic (por exemplo, 10 dias) é convertido em tempo equivalente para o plano Premium. Neste exemplo, 10 dias de Básico equivalem a 5 dias de Premium.
- A próxima data de renovação do usuário é ajustada para incluir esse período proporcional. Portanto, a data de renovação passa a ser 25 de maio (20 de abril + 1 mês + 5 dias).
- As renovações seguintes vão ocorrer mensalmente a partir de 25 de maio.
Snippet de código
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Fazer upgrade com CHARGE_FULL_PRICE
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Premium.
O usuário recebe um upgrade imediato para o plano Premium. O valor a ser pago imediatamente é o preço total do plano Premium: US$ 9,99. Qualquer valor restante do plano Basic é convertido em tempo no novo plano Premium, estendendo um pouco a primeira data de renovação. Depois disso, o valor da renovação será de US $9,99 por ciclo.
Fazer downgrade com CHARGE_FULL_PRICE
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Lite.
O usuário recebe um downgrade imediato para o plano Lite, e um novo ciclo de faturamento é iniciado. O valor a ser pago imediatamente é o preço total da meta de US $2,99. A parte não utilizada do plano Basic é proporcional ao tempo do novo plano Lite, estendendo a primeira data de renovação. Depois disso, o valor da renovação será de US $2,99 por ciclo.
Conclusão
Nesta seção, explicamos como o CHARGE_FULL_PRICE cobra do usuário o valor total no dia da troca, iniciando um novo ciclo de faturamento imediatamente. Qualquer saldo restante do plano anterior será aplicado linearmente à próxima data de renovação.
8. WITHOUT_PRORATION
Nesse modo de substituição, o item de assinatura recebe upgrade ou downgrade imediatamente, e o novo preço é cobrado quando a assinatura é renovada.
Exemplo de cenário
Um usuário tem o plano Basic (US$ 4,99 por mês a partir de 1º de abril). Em 20 de abril, o usuário quer mudar para o plano Premium (US$ 9,99 por mês).
Nesse caso:
- O usuário recebe acesso ao plano Premium imediatamente.
- O usuário não precisa pagar o preço mais alto de US $9,99 até a próxima data de renovação da assinatura (1º de maio).
Snippet de código
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Fazer upgrade com WITHOUT_PRORATION
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Premium.
O usuário recebe um upgrade imediato para o plano Premium, mantendo a data de renovação atual. O valor a ser pago imediatamente é de US $0,00. O usuário tem acesso ao plano Premium pelo tempo restante do ciclo atual antes de mudar para o novo valor de renovação de US $9, 99 na próxima data de faturamento.
Fazer downgrade com WITHOUT_PRORATION
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Lite.
O usuário faz downgrade para o plano Lite imediatamente e perde os recursos do Basic que pagou. O valor a ser pago imediatamente é de US $0,00. O ciclo de faturamento continua sem alterações, e o usuário vai pagar a nova taxa mais baixa de US $2, 99 na próxima renovação programada.
Conclusão
Esta seção demonstrou como WITHOUT_PRORATION troca imediatamente os direitos do usuário sem uma cobrança de finalização da compra, deixando o ciclo de faturamento intacto.
9. DEFERRED
Nesse modo de substituição, o item de assinatura só recebe upgrade ou downgrade quando a assinatura é renovada, mas a nova compra é emitida imediatamente. O item atual é definido como não renovável e expira no final do ciclo de faturamento atual, enquanto o direito de acesso recém-solicitado começa logo em seguida.
Exemplo de cenário
Um usuário tem o plano Basic (US$ 4,99 por mês a partir de 1º de abril). Em 20 de abril, o usuário quer mudar para o plano Premium (US$ 9,99 por mês).
Nesse caso:
- O usuário não recebe uma cobrança imediata.
- O usuário continua recebendo os recursos do Basic até o fim do ciclo de faturamento atual (30 de abril).
- O plano de assinatura será atualizado automaticamente para o Premium na próxima data de renovação (1º de maio).
Snippet de código
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.DEFERRED;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Fazer upgrade com DEFERRED
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Premium.
O usuário vai permanecer no plano Basic até o fim do ciclo de faturamento atual. O valor a ser pago imediatamente é de US $0,00. Na data de renovação, o direito de acesso será atualizado para o plano Premium, e o novo valor de renovação de US $9,99 será cobrado.
Downgrade com DEFERRED
Para simular esse cenário:
- No
MainActivitydo app de exemplo, atualize oreplacementModeno snippet de código paraSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - Recrie e inicie o aplicativo.
- Cancele as assinaturas atuais (se houver) na Google Play Store e deixe que elas expirem.
- Compre o plano Basic.
- Mude para o plano Lite.
O usuário vai permanecer no plano Basic até o fim do ciclo de faturamento atual. O valor a ser pago imediatamente é de US $0,00. Na data de renovação, o direito será atualizado para o plano Lite, e o novo valor de renovação de US $2,99 será cobrado.
Conclusão
Esta seção explicou como o modo de substituição DEFERRED adia um upgrade ou downgrade até o final do período pago de um usuário ativo. Isso o torna ideal para fazer downgrade e evitar a perda de recursos já comprados.
10. Processamento de back-end e do lado do cliente
Depois que um usuário aciona uma substituição de assinatura bem-sucedida, verifique se o app e o back-end processam corretamente a mudança para evitar problemas como interrupções de serviço ou cobrança dupla.
Exemplo
- O usuário tem um plano mensal Básico (product_id
basic_plane purchase_tokenbasic_purchase_token_123). - O usuário muda para um plano Premium usando um modo de substituição imediata (um de
WITHOUT_PRORATION,WITH_TIME_PRORATION,CHARGE_PRORATED_PRICE,CHARGE_FULL_PRICE) - Depois que a troca for concluída, o Google vai tratar a assinatura como NOVA e criar um token de compra novo e diferente para o plano Premium (product_id
premium_plane purchase_tokenpremium_purchase_token_123).
Processamento do lado do cliente
onPurchasesUpdated
Quando a compra substituta for concluída, o evento PurchasesUpdatedListener será acionado. Mesmo que tenha sido uma mudança, o Google Play trata o plano Premium como uma compra totalmente nova.
O app vai receber um objeto Purchase que contém o token de compra premium_purchase_token_123 e o product_id premium_plan. Você precisa tratar isso exatamente como um novo assinante: verifique o token e prepare-se para conceder acesso.
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {
for (Purchase purchase : purchases) {
// purchase.getPurchaseToken() = premium_purchase_token_123
// purchase.getProducts() will contain premium_plan
// Verify the purchase and grant entitlement
handleNewPurchase(purchase);
}
}
}
queryPurchasesAsync
O queryPurchasesAsync retorna apenas as assinaturas ativas compradas no seu app. Use esse método para determinar qual direito mostrar ao usuário. Para substituições imediatas, o queryPurchasesAsync() vai parar de retornar o token de compra BASIC antigo e vai retornar apenas o novo token de compra PREMIUM.
Sempre que o app for retomado ou uma compra for concluída, chame esse método. Se o token Premium estiver presente, conceda imediatamente os recursos Premium e remova os recursos básicos.
Processamento de back-end (RTDN)
Quando uma substituição ocorre, o Google Play envia uma Notificação do desenvolvedor em tempo real (RTDN) para o tópico configurado do Pub/Sub.
- No caso de substituição imediata, o Google envia uma RTDN
SUBSCRIPTION_PURCHASEDcom o novo token de compra.Exemplo de payload de RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - Quando o servidor receber o novo token de compra da RTDN, chame a API
purchases.subscriptionsV2com o novo token para buscar os detalhes da compra. A resposta da API contém um campolinkedPurchaseTokenusado para determinar se o token de compra se refere a uma nova compra de assinatura ou a uma substituição de assinatura. - No caso de uma substituição de assinatura,
linkedPurchaseTokense refere ao token de compra da assinatura antiga. Nesse cenário, seriabasic_purchase_token_123.Exemplo de resposta deGET purchases.subscriptionsV2curl \ 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/<application_id>/purchases/subscriptionsv2/tokens/premium_purchase_token_123' \ --header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \ --header 'Accept: application/json' { "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "...", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", // The purchase token of the subscription that was replaced (Basic Plan in this case) "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // productID of the new subscription (Premium Plan in this case) "expiryTime": "....", "autoRenewingPlan": {...}, "offerDetails": { "basePlanId": "monthly-auto-renewing" // base plan ID of the new subscription }, "itemReplacement": { // Details about the subscription replacement "productId": "subscription_basic", // productID of the old subscription (Basic Plan in this case) "replacementMode": "CHARGE_PRORATED_PRICE", // Replacement strategy used for this subscription change "basePlanId": "monthly-auto-renewing" // base plan ID of the old subscription }, "offerPhase": {...} } ], "etag": "<etag_value>" } - Você precisa confirmar a nova compra do Premium. Isso pode ser feito no app ou no back-end. Se a compra não for confirmada em até três dias, ela será reembolsada e o direito será revogado. Para mais detalhes sobre o processamento e a confirmação de compras, consulte a documentação para desenvolvedores.
Conclusão
Esta seção abordou as etapas para lidar com substituições imediatas de assinaturas no cliente e no back-end. Você aprendeu que o Google Play trata o novo plano como uma compra totalmente nova, emitindo um novo token de compra. No cliente, processe essa nova compra usando o PurchasesUpdatedListener e atualize os direitos com base na resposta do queryPurchasesAsync. No back-end, ouça as RTDNs SUBSCRIPTION_PURCHASED para o novo token, use a API purchases.subscriptionsv2 para identificar o linkedPurchaseToken da assinatura antiga e revogue imediatamente o acesso associado ao token antigo ao conceder o novo direito. Não se esqueça de sempre confirmar a nova compra.
11. Processar substituições ADIADAS
Ao contrário dos modos de substituição imediata, o ReplacementMode.DEFERRED adia a mudança de assinatura e a atualização de direitos de acesso até o final do ciclo de faturamento atual. O processamento de substituições adiadas exige uma lógica específica para garantir que os usuários recebam o direito correto no momento adequado.
Exemplo
- O usuário tem um plano mensal Básico (product_id
basic_plane purchase_tokenbasic_purchase_token_123) que será renovado em 15 de abril. - Em 1º de abril, o usuário decide mudar para um plano Premium usando
ReplacementMode.DEFERRED. - O Google cria um token de compra NOVO para o plano Premium (product_id
premium_plane purchase_tokenpremium_purchase_123) imediatamente, mas o valor a ser cobrado do usuário e o direito são programados para 15 de abril.
Processar substituição adiada
1. Logo após a conclusão do fluxo de compra (app)
- O
PurchasesUpdatedListeneré invocado após a conclusão do fluxo de compra. O app vai receber um objetoPurchasecontendo o novo token de comprapremium_purchase_token_123. No entanto, o product_id ainda se referirá aobasic_planantigo, já que o usuário tem direito apenas ao plano Básico. Você precisa tratar isso exatamente como uma nova compra e confirmar o token.@Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // purchase.getPurchaseToken() = premium_purchase_token_123 // purchase.getProducts() will contain basic_plan // Verify and acknowledge the purchase handleNewPurchase(purchase); } } } - O
queryPurchasesAsyncretorna a compra com o novo token (premium_purchase_token_123) imediatamente e o direito original (basic_plan) associado a ela. Você pode confiar nisso para continuar concedendo o direito ao plano Basic ao usuário.
2. Logo após a conclusão do fluxo de compra (back-end)
- A RTDN SUBSCRIPTION_PURCHASED é enviada imediatamente após o fluxo de compra do novo token (
premium_purchase_token_123).{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - Chame o
GET purchases.subscriptionsv2com o novo token de compra para buscar os detalhes da compra. A resposta contém dois itens de linha.- Um representa a assinatura antiga (plano básico) e tem um
expiryTimeno futuro. A assinatura antiga não será renovada e terá umdeferredItemReplacementcom a nova assinatura (plano premium). Isso indica uma substituição pendente do direito antigo após a expiração dele. - Um representando a assinatura recém-comprada. Ele não tem um valor definido para "expiryTime".
{ "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "2026-05-07T15:50:11.383Z", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // Premium Plan has no expiry time "autoRenewingPlan": {...}, "offerDetails": {...}, "itemReplacement": {. // Subscription replacement details "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {} }, { "productId": "basic_plan", // Subscription to be replaced "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time in the future "autoRenewingPlan": {}, "offerDetails": {...}, "deferredItemReplacement": { // identifier indicating this subscription will be replaced upon renewal "productId": "subscription_premium" }, "latestSuccessfulOrderId": "GPA.<order_id>", "itemReplacement": {...}, } ], "etag": "<etag>" } - Um representa a assinatura antiga (plano básico) e tem um
- Você precisa confirmar o novo token de compra. Isso pode ser feito no app ou no back-end. Para mais detalhes sobre o processamento e a confirmação de compras, consulte a documentação para desenvolvedores.
- A RTDN SUBSCRIPTION_EXPIRED é enviada para o token de compra antigo (
basic_purchase_token_123).Exemplo de payload de RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":13, // SUBSCRIPTION_EXPIRED "purchaseToken":"basic_purchase_token_123" //purchase token for the old subscription } } - Ao chamar a API
GET purchases.subscriptionsv2com o token de compra antigo, ele aparece como expirado (SUBSCRIPTION_STATE_EXPIRED). O direito de acesso do plano antigo é transferido para a nova compra pelo tempo restante.
3. Na data de substituição: primeira renovação após o fluxo de compra (app)
- O
queryPurchasesAsyncretorna a compra com o novo token (premium_purchase_token_123) e a nova assinatura associada a ela (premium_plan). - A nova compra já terá sido processada quando o fluxo de compra for concluído. Portanto, não é necessário fazer nada além de garantir que o acesso à assinatura correta seja concedido ao usuário.
4. Na data de substituição: primeira renovação após o fluxo de compra (back-end)
- Com
ReplacementMode.DEFERRED, as primeiras renovações seguem o comportamento padrão de qualquer outra renovação que esteja processando RTDNsSUBSCRIPTION_RENEWED. Não é necessário ter uma lógica especial para substituições quando isso acontece. - Chame o
GET purchases.subscriptionsv2com o novo token de compra para buscar os detalhes da compra. A resposta contém dois itens de linha.- Um representa a assinatura antiga (plano básico) e tem um
expiryTimeno passado. A assinatura antiga não terá mais um valor definido para o campodeferredItemReplacement. - Um representando a nova assinatura com um
expiryTimeno futuro e o campoautoRenewEnableddefinido comotrue.
{ "kind": "androidpublisher#subscriptionPurchaseV2", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>..0", "linkedPurchaseToken": "basic_purchase_token_123", // purchase token of the old subscription "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // New subscription "expiryTime": "2026-05-07T16:00:09.437Z", // Expiry time set in the future "autoRenewingPlan": { "autoRenewEnabled": true, // Auto Renewing Flag set to True "recurringPrice": {...} }, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {. // Details of the subscription replacement "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {...} }, { "productId": "basic_plan", // Old subscription, Does not contains the deferredItemReplacement field "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time set in the past "autoRenewingPlan": {}, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {...}, } ], "etag": "<etag>" } - Um representa a assinatura antiga (plano básico) e tem um
Conclusão
Esta seção detalhou o processamento exclusivo necessário para ReplacementMode.DEFERRED. Você aprendeu que, ao contrário dos modos imediatos, a mudança de direito só ocorre no final do ciclo de faturamento atual. Esta seção abordou as etapas necessárias para que seu app e back-end processem corretamente a compra inicial, confirmem o novo token e gerenciem a troca de direitos quando a assinatura antiga expirar e a nova for ativada.
12. Playground de substituição de assinatura
O recurso Replacement Playground no app de exemplo permite testar upgrades e downgrades de assinaturas para os produtos por assinatura configurados na sua conta do Google Play Console. Esta seção descreve como usar o recurso Replacement Playground.
Configuração
Para usar o recurso Playground de substituição, confira o seguinte:
- O
packageIdno arquivobuild.gradlecorresponde ao aplicativo configurado no Google Play Console. - Sua conta de usuário de teste está inscrita como testador de licença no Google Play Console. Para saber mais sobre o teste de licença, consulte Testar a implementação de faturamento do app.
Playground de substituição de assinatura
O app de exemplo inclui uma guia Replacement Playground, que permite simular mudanças de assinatura. É possível consultar as assinaturas definidas no Play Console e testar a troca entre elas usando vários modos de substituição. Esse ambiente de simulação ajuda você a entender como os diferentes modos afetam os ciclos de faturamento e os direitos das suas assinaturas. Assim, você pode determinar quais opções são mais adequadas às necessidades da sua empresa.
Para simular substituições usando o playground, siga estas etapas:
- Acesse a guia Playground.
- Se você tiver uma assinatura ativa:ela vai ser destacada. Esta é a assinatura que será substituída.

- Se você não tiver uma assinatura ativa:primeiro, compre uma.
- O Playground lista os planos Basic, Premium e Lite criados para este codelab por padrão.
- Para testar com outros planos configurados no Play Console, clique em Adicionar plano personalizado e pesquise por
productIdebasePlanId. - Compre a assinatura selecionada.
- A assinatura ativa recém-comprada do usuário vai aparecer.

- Selecione a assinatura de destino para a qual o usuário quer mudar.
- Selecione um Modo de substituição para a transição.

- Clique no botão Testar substituição para simular a substituição da assinatura.
- Você vai encontrar a página inferior do Google Play Faturamento com os detalhes calculados da substituição da assinatura, como cobranças imediatas e ajustes no ciclo de faturamento.

- Conclua o pagamento.
- Acesse a página Gerenciar assinaturas no app Google Play Store para conferir as mudanças nas assinaturas ativas, além de detalhes sobre as datas e os preços de renovação atualizados.

13. Próximas etapas
- Saiba como maximizar sua integração do Play Faturamento.
- Não se esqueça de seguir as práticas recomendadas para verificar e processar compras no seu back-end seguro assim que os usuários começarem a comprar esses produtos.
Documentos de referência
14. Parabéns
Parabéns! Você implementou substituições de assinatura com vários modos de rateio e configurou o processamento de back-end para transições de plano.
O que você aprendeu
- Como configurar
SubscriptionProductReplacementParamscom modos de substituição específicos. - A diferença entre upgrades imediatos e downgrades adiados.
- Como desativar tokens de assinatura antigos usando
linkedPurchaseTokencom RTDNs.
Pesquisa
Seu feedback sobre este codelab é muito importante. Reserve alguns minutos para responder à nossa pesquisa.