Como verificar a compra do aplicativo Android no servidor (Google Play no faturamento do aplicativo v3)

96

Tenho um aplicativo simples (requer login de usuário com conta). Eu ofereço alguns recursos premium para usuários pagos, como mais conteúdo de notícias.

Preciso registrar se o usuário comprou este item no banco de dados do meu servidor. Quando forneço conteúdo de dados ao dispositivo do usuário, posso verificar o status do usuário e fornecer conteúdo diferente para o usuário pago.

Eu verifiquei o exemplo oficial do Trivialdrive fornecido pelo Google, ele não fornece nenhum código de exemplo para verificação do lado do servidor. Aqui estão minhas perguntas.

  1. Descobri que o exemplo usa a chave pública do meu aplicativo para verificar a compra, não parece bom, acho que posso simplesmente mover o processo de verificação para o meu servidor combinado com as credenciais de login do usuário para ver se a compra do usuário foi concluída e, em seguida, atualizar o banco de dados.
  2. Também há a API de compra que posso usar para consultar, o que preciso é passar o purchaseToken do usuário para o servidor.

Não tenho certeza de qual método devo seguir para verificar a compra do usuário e marcar o status do usuário em meu banco de dados, talvez ambos?

E temo que haja uma situação, se um usuário comprou este item do google play, mas por algum motivo, bem naquele momento, quando meu aplicativo lançou a verificação para o meu servidor, a conexão de rede caiu ou meu próprio servidor caiu , o usuário acabou de pagar o dinheiro no google play mas eu não registrei a compra no meu servidor? O que devo fazer, como posso lidar com esta situação.

virsir
fonte
Você provavelmente deve remover o sinalizador ios desta questão.
Gustavo Guevara

Respostas:

160

Parece que você está procurando uma maneira de verificar se o usuário possui recursos premium habilitados em sua conta, então é por aqui que eu começaria;

Certifique-se de que haja um sinalizador de algum tipo em seu banco de dados indicando se o usuário tem recursos premium e inclua-o na carga útil de resposta da API ao solicitar informações da conta. Este sinalizador será sua autoridade principal para "recursos premium".

Quando um usuário faz uma compra no aplicativo, armazene em cache os detalhes (token, id do pedido e id do produto) localmente no cliente (ou seja, o aplicativo) e envie-os para sua API.

Sua API deve então enviar purchaseTokenpara a API do desenvolvedor do Google Play para validação.

Algumas coisas podem acontecer a partir daqui:

  1. O recibo é válido, sua API responde ao cliente com um código de status 200 Ok
  2. O recibo é inválido, sua API responde ao cliente com um código de status 400 Bad Request
  3. API do Google Play está inativa, sua API responde com um código de status 502 Bad Gateway

No caso de 1. ou 2. (códigos de status 2xx ou 4xx) seu cliente limpa o cache de detalhes de compra porque não precisa mais deles porque a API indicou que foi recebido.

Após uma validação bem-sucedida (caso 1.), você deve definir o premiumsinalizador como verdadeiro para o usuário.

No caso de 3. (código de status 5xx) ou um timeout da rede, o cliente deve continuar tentando até receber um código de status 2xx ou 4xx de sua API.

Dependendo dos seus requisitos, você pode esperar alguns segundos antes de enviar novamente ou apenas enviar os detalhes para sua API sempre que o aplicativo for iniciado novamente ou sair do fundo se os detalhes da compra estiverem presentes no cache do aplicativo.

Esta abordagem deve cuidar de tempos limite de rede, servidores indisponíveis, etc.

Existem agora algumas questões que você precisa considerar:

O que deve acontecer imediatamente após uma compra? O aplicativo deve esperar até que a validação seja bem-sucedida antes de fornecer conteúdo premium ou deve conceder acesso provisoriamente e retirá-lo se a validação falhar?

Conceder acesso provisório a recursos premium facilita o processo para a maioria de seus usuários, mas você concederá acesso a vários usuários fraudulentos enquanto sua API valida o purchaseToken.

Dito de outra forma: a compra é válida até que seja comprovada a fraude ou; fraudulento até que seja comprovado como válido?

Para identificar se o usuário ainda tem uma assinatura válida quando seu período de assinatura chegar para renovação, você precisará agendar uma revalidação no purchaseTokenpara ser executado no expiryTimeMillisque foi retornado no resultado .

Se expiryTimeMillisestiver no passado, você pode definir o premiumsinalizador como falso. Se estiver no futuro, reprograme-o novamente para o novo expiryTimeMillis.

Por último, para garantir que o usuário tenha acesso premium (ou não), seu aplicativo deve consultar sua API para obter os detalhes do usuário na inicialização do aplicativo ou quando ele sai do segundo plano.

Marc Greenstock
fonte
Para aplicativos pagos, como vou receber o recibo do google?
Merbin Joe
2
Oi! Não há como acessar o histórico de assinaturas no google? Como evitar a perda do fato de que o cubscription já foi comprado no caso de o app travar no momento de armazenar o purchaseToken?
scythargon
2
Eu tenho um problema semelhante ... em vez de permitir que o aplicativo envie o token para a api, não seria mais confiável instruir o servidor de desenvolvedor do Google a fazer isso com uma notificação push direto para minha api?
Gianluca Ghettini
Para assinaturas que foram canceladas, a API do desenvolvedor do Google Play ainda retornará 200 após o cancelamento, se o mesmo token de compra antigo for usado para validação.
Cezar Cobuz
Portanto, para uma assinatura, você está sugerindo que, após a primeira chamada no servidor, armazenemos o token de compra e a ID do produto e agendemos outra chamada de verificação (execute novamente a mesma solicitação) quando o expiryTimeMillis acontecer. É assim que devemos verificar a validade da assinatura? Existe alguma orientação do Android sobre como fazer isso? A Apple conseguiu um vídeo WWDC sobre isso que explica as boas práticas muito claramente, mas não consegue encontrar muito sobre a Play Store.
schankam de
26

A documentação sobre isso é confusa e estranhamente prolixa com as coisas que são quase inconseqüentes, enquanto deixa a documentação realmente importante quase desvinculada e super difícil de encontrar. Isso deve funcionar muito bem na plataforma de servidor mais popular que pode executar as bibliotecas de cliente API do Google, incluindo Java, Python, .Net e NodeJS, entre outras. Nota: Eu testei apenas o cliente Python api conforme mostrado abaixo.

Passos necessários:

  1. Faça um projeto de API, a partir do link de acesso à API em seu console do Google Play

  2. Faça uma nova conta de serviço, salve a chave privada JSON que é gerada. Você precisará levar este arquivo para o seu servidor.

  3. Pressione Concluído na seção da conta de serviço do Play console para atualizar e, em seguida, conceda acesso à conta de serviço

  4. Obtenha uma biblioteca cliente API do Google para sua plataforma de servidor em https://developers.google.com/api-client-library

  5. Use a biblioteca de cliente de sua plataforma específica para construir uma interface de serviço e ler diretamente o resultado de sua verificação de compra.

Você não precisa se preocupar com escopos de autorização, fazendo chamadas de solicitações personalizadas, atualizando tokens de acesso, etc. a biblioteca cliente da API cuida de tudo. Aqui está um exemplo de uso da biblioteca Python para verificar uma assinatura:

Primeiro, instale o cliente API do Google em seu pipenv desta forma:

$ pipenv install google-api-python-client

Em seguida, você pode configurar as credenciais do cliente API usando o arquivo json de chave privada para autenticar a conta de serviço.

credentials = service_account.Credentials.from_service_account_file("service_account.json")

Agora você pode verificar as compras de assinaturas ou compras de produtos usando a biblioteca, diretamente.

#Build the "service" interface to the API you want
service = googleapiclient.discovery.build("androidpublisher", "v3", credentials=credentials)

#Use the token your API got from the app to verify the purchase
result = service.purchases().subscriptions().get(packageName="your.app.package.id", subscriptionId="sku.name", token="token-from-app").execute()
#result is a python object that looks like this ->
# {'kind': 'androidpublisher#subscriptionPurchase', 'startTimeMillis': '1534326259450', 'expiryTimeMillis': '1534328356187', 'autoRenewing': False, 'priceCurrencyCode': 'INR', 'priceAmountMicros': '70000000', 'countryCode': 'IN', 'developerPayload': '', 'cancelReason': 1, 'orderId': 'GPA.1234-4567-1234-1234..5', 'purchaseType': 0}

A documentação da interface de serviço da plataforma para a API do desenvolvedor do jogo não está vinculada de uma maneira fácil de encontrar, para alguns é francamente difícil de encontrar . Aqui estão os links para as plataformas populares que encontrei:

Python | Java | .NET | PHP | NodeJS (Github TS) | Go (Github JSON)

Dhiraj Gupta
fonte
5
Concordo, a documentação é horrível ... Alguma ideia de como fazer isso com o Firebase (Firestore) e as funções do Cloud como back-end?
Jeff Padgett
Se suas funções de nuvem estão em NodeJS, talvez você possa usar o link NodeJS acima para fazer a biblioteca de cliente API funcionar.
Dhiraj Gupta
17

Exemplo completo de uso da biblioteca cliente de API do Google para PHP :

  1. Configure seu projeto do Google e acesse o Google Play para sua conta de serviço, conforme descrito na resposta de Marc aqui https://stackoverflow.com/a/35138885/1046909 .

  2. Instale a biblioteca: https://developers.google.com/api-client-library/php/start/installation .

  3. Agora você pode verificar seu recibo da seguinte forma:

    $client = new \Google_Client();
    $client->setAuthConfig('/path/to/service/account/credentials.json');
    $client->addScope('https://www.googleapis.com/auth/androidpublisher');
    $service = new \Google_Service_AndroidPublisher($client);
    $purchase = $service->purchases_subscriptions->get($packageName, $productId, $token);

    Depois que $ compra é uma instância de Google_Service_AndroidPublisher_SubscriptionPurchase

    $purchase->getAutoRenewing();
    $purchase->getCancelReason();
    ...
MingalevME
fonte
Isso não está funcionando, continuo recebendo (401) Login obrigatório e setAuthConfig não aceita as credenciais da conta de serviço json
Raulnd
Este funcionou para mim putenv ('GOOGLE_APPLICATION_CREDENTIALS = credentials.json'); $ client = new Google_Client (); $ client-> useApplicationDefaultCredentials (); $ client-> addScope (' googleapis.com/auth/androidpublisher' ); $ service = new Google_Service_AndroidPublisher ($ client); $ compra = $ serviço-> compras_produtos-> obter ($ packageName, $ productId, $ token); var_dump ($ compra);
Raulnd
Essa coisa é no caso de faturamento inapp. E se eu quiser obter orderId em meu banco de dados sempre que o usuário comprar meu aplicativo na Play Store em vez de no aplicativo?
Ankesh kumar Jaisansaria
stackoverflow.com/questions/48662787/… Por favor, veja esta pergunta. Estou procurando uma resposta para esta pergunta. Isso também tem recompensa ativa
Ankesh kumar Jaisansaria
@MingalevME E se o formato do token for inválido e o PHP receber um erro fatal, como faço para detectar esse erro?
alexx0186
12

Você pode tentar usar Purchases.subscriptions: get server-side. Leva packageName, subscriptionId e token como parâmetros e requer autorização .

Verifica se a compra de uma assinatura do usuário é válida e retorna seu tempo de expiração.

Se for bem-sucedido, este método retorna um recurso Purchases.subscriptions no corpo da resposta.

aleatória
fonte
9
Estou tendo sérios problemas para fazer a autorização funcionar.
8
Seriamente. Para saber como as compras são críticas para alguns aplicativos, o suporte e a documentação são fúteis. Isso é o que você precisa fazer no servidor: github.com/google/… . Mais informações aqui: stackoverflow.com/questions/35127086/…
usuário
0

Eu respondo a esta preocupação

a conexão de rede caiu ou meu próprio servidor caiu, o usuário acabou de pagar o dinheiro no google play mas não registrei a compra no meu servidor? O que devo fazer, como posso lidar com esta situação.

A situação é:

O usuário compra o item 'abc' usando o serviço google play -> retornar OK -> falha ao verificar com o servidor por alguns motivos, como falta de conexão com a Internet.

A solução é:

No lado do cliente, antes de mostrar o botão 'Google Wallet', você verifica se o item 'abc' já pertence a ele.

  • se sim, verifique com o servidor novamente
  • se não, mostre o botão 'Google Wallet'.

Compra compra = mInventory.getPurchase ('abc');

if (purchase != null) // Verify with server 

else // show Google Wallet button

https://developer.android.com/google/play/billing/billing_reference.html#getSkuDetails

Thanhbinh84
fonte
4
Não entendo por que validar no servidor é mais seguro do que validar no aplicativo. No final do dia, é o aplicativo que desbloqueia os recursos, então ainda é possível remover ou inverter o código no aplicativo que verifica se a resposta do servidor está "OK"
Gianluca Ghettini
2
@GianlucaGhettini porque, às vezes, o servidor é o que fornece o serviço adquirido, não o aplicativo, além disso, o aplicativo pode ser submetido a engenharia reversa e, com alguma dificuldade, o processo de verificação pode ser hackeado.
Mohyaddin Alaoddin