Olá. Sou a zm soft, que se registrou como desenvolvedor no ano passado (final de 2023) e começou a lançar aplicativos. Também planejamos lançar um aplicativo para desenvolvedores para superar juntos o teste fechado através da cooperação entre desenvolvedores, então confira se estiver interessado.
Vocês já implementaram compras no aplicativo? Para desenvolvedores de apps, fazer com que os usuários fiquem satisfeitos e receber o pagamento por isso é o melhor, e é o momento em que o esforço do desenvolvimento é recompensado. Desta vez, quero escrever sobre como alcançar isso.
O Que São Compras no Aplicativo
Como já sabem, as compras no aplicativo são classificadas em dois tipos:
- Itens consumíveis
- Itens de assinatura periódica
Ambos adotam a abordagem de acessar itens configurados previamente na Play Store através da Google Play Billing Library, e uma parte da receita obtida é paga ao Google como taxa. Do ponto de vista da implementação, ambos são similares, mas os itens de assinatura periódica têm seus próprios pontos de atenção. Explicarei os pontos de atenção com base na minha experiência pessoal.
Configuração da Play Store
Registro de Itens
Primeiro, registre os itens, pois não é possível exibi-los sem registro. O preço, o nome, etc., incluindo se realmente usará esse item, podem ser alterados posteriormente, então dados provisórios estão bem. No entanto, apenas o ID não pode ser alterado, então se você estiver pensando em usar itens criados para teste no ambiente de produção após modificá-los, é melhor registrá-los com IDs reutilizáveis como [product_1,2,3...] ou [sub_1,2,3...]. O registro pode ser feito a partir de [Monetize], onde [In-app products] e [Subscriptions] são, respectivamente, itens consumíveis e de assinatura periódica. Cada item pode ser registrado com o botão [Create xx].

Basicamente, você pode seguir a tela de entrada, mas o que foi confuso foi a configuração de preços para os itens de assinatura periódica. No início, não sabia como definir preços para todas as regiões de uma vez. Pensei que teria que inserir cada região individualmente, mas pode ser feito na seguinte ordem: [Set prices] - [Country / region] - [Set price].

Ao pressionar o botão, aparece o seguinte diálogo que permite configurar tudo de uma vez.

Registro de Conta de Teste
Em seguida, registre a conta de teste. Se você realizar um teste de compra sem registrá-la, ocorrerá um pagamento real, então tome cuidado. O registro da conta de teste é feito registrando uma lista de e-mails. O registro pode ser feito na primeira tela (tela do desenvolvedor) ao fazer login no Play Console através de [Settings] - [License testing].

Ao realizar o processo de compra do aplicativo com um usuário registrado na lista de e-mails, as informações de pagamento serão exibidas como "cartão de teste", permitindo realizar testes sem pagamento real.
Trabalho de Implementação
A implementação no lado do aplicativo requer o seguinte trabalho:
- Importação da biblioteca
- Conexão com a loja e obtenção de informações de itens
- Implementação da tela de exibição de itens
- Solicitação de compra
- Processamento ao completar a compra
A seguir, explicarei cada um em detalhes.
Importação da Biblioteca
A importação da biblioteca requer o seguinte:
- Modificação do build.gradle
- Modificação do android.manifest
Exemplo de modificação do build.gradle:
dependencies {
implementation "com.android.billingclient:6.0.0"
}
Exemplo de modificação do manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="com.android.vending.BILLING" />
<application
Por favor, consulte a documentação oficial para a versão, etc.
Conexão com a Loja e Obtenção de Informações de Itens
Inicializando o BillingClient e executando o startConnection, é possível comunicar-se com a loja. As informações de cada item podem ser obtidas com queryProductDetailsAsync. Para mais detalhes, consulte a documentação oficial. No meu caso, por alguma razão a obtenção em lote não funcionou bem, então primeiro obtive a lista de itens e depois obtive os detalhes de cada item individualmente com queryProductDetailAsync. O item obtido (SKU) pode ser identificado como consumível ou de assinatura periódica pelo seu tipo, inapp ou subs.
Implementação da Tela de Exibição de Itens
Após obter as informações dos itens, exiba-as em uma lista para que a compra possa ser selecionada. Ao lidar com itens de assinatura periódica, é necessário cumprir com a Subscription Policy, e no meu caso, as atualizações do aplicativo foram rejeitadas consecutivamente pelas seguintes duas razões:
- Localização incompleta do preço e das condições
- Descrição incompleta das condições da oferta
Primeiro, sobre a localização incompleta: o motivo foi a exibição do período (ex.: $10/month). O problema é que a palavra "month" não estava traduzida quando executado com a configuração de região de um idioma não suportado na tradução. Ao obter informações com o BillingClient, o valor do preço é recuperado como a string formattedPrice que inclui informações de unidade, portanto não é necessário traduzi-lo no aplicativo. Por outro lado, as informações do período são notificadas no formato ISO 8601 como P1M, e isso deve ser traduzido no aplicativo. Tratei disso adicionando processos de conversão para cada idioma da seguinte forma:
fun formatBillingPeriod(billingPeriod: String, languageCode: String): String {
return when(languageCode) {
"en" -> {
when (billingPeriod) {
"P1W" -> "weekly"
"P1M" -> "monthly"
"P3M" -> "every 3 months"
"P6M" -> "every 6 months"
"P1Y" -> "annually"
else -> "unknown"
}
}
"ja" -> {
when (billingPeriod) {
"P1W" -> "週間"
"P1M" -> "月額"
"P3M" -> "3ヶ月ごと"
"P6M" -> "6ヶ月ごと"
"P1Y" -> "年額"
else -> "不明"
}
}
"fr" -> {
when (billingPeriod) {
"P1W" -> "hebdomadaire"
"P1M" -> "mensuel"
"P3M" -> "tous les 3 mois"
"P6M" -> "tous les 6 mois"
"P1Y" -> "annuel"
else -> "inconnu"
}
}
"es" -> {
when (billingPeriod) {
"P1W" -> "semanal"
"P1M" -> "mensual"
"P3M" -> "cada 3 meses"
"P6M" -> "cada 6 meses"
"P1Y" -> "anual"
else -> "desconocido"
}
}
"de" -> {
when (billingPeriod) {
"P1W" -> "wöchentlich"
"P1M" -> "monatlich"
"P3M" -> "alle 3 Monate"
"P6M" -> "alle 6 Monate"
"P1Y" -> "jährlich"
else -> "unbekannt"
}
}
else -> "unknown"
}
}
A seguir, sobre a descrição incompleta das condições da oferta:

Entendi o problema, mas não sabia exatamente qual texto concreto deveria escrever para resolvê-lo. A seguir está um trecho do texto original do e-mail de rejeição que recebi:
Issue found: Violation of Subscriptions policy
Your app does not comply with the Subscriptions policy.
- Your offer does not clearly and accurately describe the terms of your trial offer or introductory pricing, including when a free trial will convert to a paid subscription, how much the paid subscription will cost, and that a user can cancel if they do not want to convert to a paid subscription.
Como solução, tomei emprestado texto de outros aplicativos. Como parece ser texto padrão em sua maior parte, pensei que era melhor seguir precedentes comprovados do que pensar do zero.
Solicitação de Compra
Depois que o usuário pode selecionar um item da tela, finalmente chega o processamento de compra do item. Executando o fluxo de compra para o item obtido, a tela de compra real pode ser invocada.
Testes
Os testes podem ser realizados sem incorrer em cobranças reais fazendo login com a conta de teste preparada no início. Os dois pontos de atenção aqui são:
- A execução do fluxo de compra é realizada com o aplicativo registrado na loja
- Para itens de assinatura periódica, o período é definido de forma personalizada
Em relação à execução do fluxo de compra, se o aplicativo for uma compilação de depuração, um erro será exibido na tela de compra e o fluxo não poderá ser executado.
Em relação aos itens de assinatura periódica, ao avançar para a tela de compra real, o pagamento com cartão de teste é exibido. Nesse momento, o período de renovação é exibido na tela de compra, mas o período exibido é diferente do período realmente configurado no item. No meu caso, eram exibidos 5 minutos. Parece ser uma especificação que exibe um período fixo extremamente curto para o comportamento de renovação da assinatura. (Pensei que tinha configurado algo errado e fiquei revisando as configurações por um tempo.)
Conclusão
No início parece difícil, mas uma vez que se compreende a imagem geral, as compras no aplicativo em si podem ser implementadas surpreendentemente facilmente consultando as informações disponíveis publicamente como a documentação oficial. No entanto, para as assinaturas periódicas, há armadilhas que não se pode descobrir a não ser que se tente, então espero que os pontos em que tropecei sirvam de referência para os desenvolvedores que as implementarem no futuro.