Come verificare l'acquisto per l'app Android sul lato server (Google Play nella fatturazione dell'app v3)


96

Ho un'app semplice (richiede l'accesso utente con account). Fornisco alcune funzionalità premium per gli utenti a pagamento, come più contenuti di notizie.

Devo registrare se l'utente ha acquistato questo articolo nel database del mio server. Quando fornisco il contenuto dei dati al dispositivo dell'utente, posso quindi controllare lo stato dell'utente e fornire contenuti diversi per l'utente a pagamento.

Ho controllato l'esempio ufficiale di Trivialdrive fornito da Google, non fornisce alcun codice di esempio per la verifica lato server, ecco le mie domande.

  1. Ho scoperto che l'esempio utilizza la chiave pubblica della mia app all'interno per verificare l'acquisto, non sembra buono, penso di poter semplicemente spostare il processo di verifica sul mio server combinato con le credenziali di accesso dell'utente per vedere se l'acquisto dell'utente è stato completato, quindi aggiornare il database.
  2. Inoltre c'è l' API di acquisto che posso usare per interrogare, ciò di cui ho bisogno è passare il token di acquisto dell'utente al server.

Non sono sicuro di quale metodo dovrei adottare per verificare l'acquisto dell'utente e contrassegnare lo stato dell'utente nel mio database, forse entrambi?

E temo che ci sia una situazione, se un utente ha acquistato questo articolo da Google Play, ma per qualche motivo, proprio in quel momento, quando la mia app ha avviato la verifica sul mio server, la connessione di rete è interrotta o il mio server è inattivo , l'utente ha appena pagato i soldi in Google Play ma non ho registrato l'acquisto nel mio server? Cosa devo fare, come posso affrontare questa situazione.


Probabilmente dovresti rimuovere il flag ios da questa domanda.
Gustavo Guevara

Risposte:


160

Sembra che quello che stai cercando sia un modo per verificare se l'utente ha funzionalità premium abilitate sul proprio account, quindi è da qui che inizierei;

Assicurati che nel tuo database sia presente un flag di qualche tipo che indica se l'utente dispone di funzionalità premium e includilo nel payload della risposta API quando richiedi le informazioni sull'account. Questo flag sarà la tua autorità principale per le "funzionalità premium".

Quando un utente effettua un acquisto in-app, memorizza nella cache i dettagli (token, ID ordine e ID prodotto) localmente sul client (ovvero l'app), quindi invialo alla tua API.

Il tuo API dovrebbe quindi inviare il purchaseTokenal Google Play Developer API per la convalida.

Alcune cose potrebbero accadere da qui:

  1. La ricevuta è valida, la tua API risponde al cliente con un codice di stato 200 Ok
  2. La ricevuta non è valida, la tua API risponde al client con un codice di stato 400 Bad Request
  3. L'API di Google Play è inattiva, la tua API risponde con un codice di stato 502 Bad Gateway

Nel caso di 1. o 2. (codici di stato 2xx o 4xx) il tuo client svuota la cache dei dettagli dell'acquisto perché non ne ha più bisogno perché l'API ha indicato che è stato ricevuto.

Dopo una convalida riuscita (caso 1.), è necessario impostare il premiumflag su true per l'utente.

Nel caso di 3. (codice di stato 5xx) o di un timeout di rete, il client dovrebbe continuare a provare finché non riceve un codice di stato 2xx o 4xx dalla tua API.

A seconda delle tue esigenze, potresti aspettare qualche secondo prima di inviare di nuovo o semplicemente inviare i dettagli alla tua API ogni volta che l'app viene avviata di nuovo o esce dallo sfondo se i dettagli dell'acquisto sono presenti nella cache dell'app.

Questo approccio dovrebbe occuparsi dei timeout di rete, dei server non disponibili, ecc.

Ci sono ora alcune domande che devi considerare:

Cosa dovrebbe accadere subito dopo un acquisto? L'app deve attendere che la convalida abbia esito positivo prima di fornire contenuti premium o dovrebbe concedere provvisoriamente l'accesso e portarlo via se la convalida non riesce?

La concessione dell'accesso provvisorio alle funzionalità premium semplifica il processo per la maggior parte dei tuoi utenti, ma concederai l'accesso anche a un numero di utenti fraudolenti mentre la tua API convalida il file purchaseToken.

In altre parole: l'acquisto è valido fino a prova fraudolenta o; fraudolento fino a prova contraria?

Al fine di identificare se l'utente ha ancora un abbonamento valido quando il periodo di abbonamento scade per il rinnovo, sarà necessario pianificare una nuova convalida in modo purchaseTokenche venga eseguito nel momento in expiryTimeMilliscui è stato restituito nel risultato .

Se expiryTimeMillisè nel passato, puoi impostare il premiumflag su false. Se è in futuro, riprogrammalo di nuovo per il nuovo expiryTimeMillis.

Infine, per garantire che l'utente disponga o meno di un accesso premium, la tua app dovrebbe richiedere alla tua API i dettagli degli utenti all'avvio dell'app o quando esce dallo sfondo.


Per le app a pagamento, come riceverò la ricevuta da Google?
Merbin Joe,

2
Ciao! Non c'è modo di accedere alla cronologia degli abbonamenti su Google? Come evitare di perdere il fatto che utilizzava già acquistato cubscription nel caso in cui l'app si arresti in modo anomalo al momento della memorizzazione del token di acquisto?
scythargon

2
Ho un problema simile .. invece di lasciare che l'app invii il token all'API non sarebbe più affidabile istruire il server sviluppatore di Google a farlo con una notifica push direttamente alla mia API?
Gianluca Ghettini

Per gli abbonamenti che sono stati annullati, l'API per sviluppatori di Google Play restituirà ancora 200 dopo l'annullamento, se per la convalida viene utilizzato lo stesso vecchio token di acquisto.
Cezar Cobuz,

Quindi, per un abbonamento, stai suggerendo che dopo la prima chiamata sul server, memorizziamo il token di acquisto e l'ID prodotto e pianifichiamo un'altra chiamata di verifica (rieseguendo la stessa richiesta) quando si verifica il termine expiryTimeMillis? È così che dovremmo verificare la validità dell'abbonamento? Esistono linee guida di Android su come farlo? Apple ha ottenuto un video del WWDC su di esso che spiega la buona pratica in modo abbastanza chiaro, ma non riesce a trovare molto su Play Store.
schankam

26

La documentazione su questo è confusa e stranamente prolissa con le cose che sono quasi irrilevanti mentre lascia la documentazione effettivamente importante quasi scollegata e super difficile da trovare. Questo dovrebbe funzionare alla grande sulla piattaforma server più popolare in grado di eseguire le librerie client API di Google, inclusi Java, Python, .Net e NodeJS, tra gli altri. Nota: ho testato solo il client API Python come mostrato di seguito.

Passaggi necessari:

  1. Crea un progetto API, dal link Accesso API nella tua console Google Play

  2. Crea un nuovo account di servizio, salva la chiave privata JSON che viene generata. Dovrai portare questo file sul tuo server.

  3. Premi Fine nella sezione dell'account di servizio della console Play per aggiornare e quindi concedere l'accesso all'account di servizio

  4. Ottieni una libreria client API di Google per la tua piattaforma server da https://developers.google.com/api-client-library

  5. Utilizza la libreria client della tua piattaforma specifica per creare un'interfaccia di servizio e leggere direttamente il risultato della verifica dell'acquisto.

Non è necessario preoccuparsi degli ambiti di autorizzazione, effettuare chiamate di richieste personalizzate, aggiornare i token di accesso, ecc. La libreria client api si occupa di tutto. Ecco un esempio di utilizzo della libreria Python per verificare un abbonamento:

Innanzitutto, installa il client API di Google nel tuo pipenv in questo modo:

$ pipenv install google-api-python-client

Quindi è possibile impostare le credenziali del client API utilizzando il file json della chiave privata per autenticare l'account del servizio.

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

Ora puoi verificare direttamente gli acquisti di abbonamenti o di prodotti utilizzando la libreria.

#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}

La documentazione per l'interfaccia di servizio della piattaforma per l'API dello sviluppatore di giochi non è collegata in modo facile da trovare, per alcuni è addirittura difficile da trovare . Ecco i link per le piattaforme popolari che ho trovato:

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


5
D'accordo, la documentazione è orribile ... Qualche idea su come farlo con Firebase (Firestore) e le funzioni Cloud come backend?
Jeff Padgett

Se le tue funzioni Cloud sono in NodeJS, potresti forse utilizzare il collegamento NodeJS sopra per far funzionare la libreria API Client?
Dhiraj Gupta

17

Esempio completo di utilizzo della libreria client API di Google per PHP :

  1. Configura il tuo progetto Google e accedi a Google Play per il tuo account di servizio come descritto nella risposta di Marc qui https://stackoverflow.com/a/35138885/1046909 .

  2. Installa la libreria: https://developers.google.com/api-client-library/php/start/installation .

  3. Ora puoi verificare la tua ricevuta nel modo seguente:

    $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);

    Dopo che $ acquisto è istanza di Google_Service_AndroidPublisher_SubscriptionPurchase

    $purchase->getAutoRenewing();
    $purchase->getCancelReason();
    ...

Questo non funziona, continuo a ricevere (401) Accesso richiesto e setAuthConfig non accetta le credenziali dell'account di servizio json
Raulnd

Questo ha funzionato per me putenv ('GOOGLE_APPLICATION_CREDENTIALS = credentials.json'); $ client = nuovo Google_Client (); $ client-> useApplicationDefaultCredentials (); $ client-> addScope (' googleapis.com/auth/androidpublisher' ); $ service = nuovo Google_Service_AndroidPublisher ($ client); $ acquisto = $ servizio-> acquisti_prodotti-> get ($ packageName, $ productId, $ token); var_dump ($ acquisto);
Raulnd

Questa cosa è in caso di fatturazione inapp. E se volessi ricevere orderId nel mio database ogni volta che l'utente acquista la mia app dal Play Store invece che da inapp?
Ankesh kumar Jaisansaria

stackoverflow.com/questions/48662787/… Si prega di consultare questa domanda. Sto cercando una risposta a questa domanda. Questo ha anche una taglia attiva
Ankesh kumar Jaisansaria

@MingalevME Cosa succede se il formato del token non è valido e PHP riceve un errore irreversibile, come posso rilevare questo errore?
alexx0186

12

Puoi provare a utilizzare Purchases.subscriptions: ottieni lato server. Accetta packageName, subscriptionId e token come parametri e richiede l' autorizzazione .

Verifica se l'acquisto dell'abbonamento di un utente è valido e restituisce la data di scadenza.

In caso di esito positivo, questo metodo restituisce una risorsa Purchases.subscriptions nel corpo della risposta.


9
Ho seri problemi per far funzionare l'autorizzazione.

8
Sul serio. Per quanto siano importanti gli acquisti per alcune app, il supporto e la documentazione sono inutili. Questo è quello che devi fare sul server: github.com/google/… . Maggiori informazioni qui: stackoverflow.com/questions/35127086/…
utente

0

Rispondo a questa preoccupazione

la connessione di rete è interrotta o il mio server è inattivo, l'utente ha appena pagato i soldi in Google Play ma non ho registrato l'acquisto nel mio server? Cosa devo fare, come posso affrontare questa situazione.

La situazione è:

L'utente acquista l'elemento "abc" utilizzando il servizio Google Play -> torna OK -> non riesce a verificare con il server per alcuni motivi, come la mancanza di connessione a Internet.

La soluzione è:

Sul lato client, prima di mostrare il pulsante "Google Wallet", controlla se l'elemento "abc" è già di proprietà.

  • se sì, verifica di nuovo con il server
  • in caso negativo, mostra il pulsante "Google Wallet".

Acquisto acquisto = 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


4
Non capisco perché la convalida sul server sia più sicura della convalida sull'app. Alla fine della giornata è l'app che sblocca le funzionalità quindi è ancora possibile rimuovere o invertire il codice nell'app che controlla se la risposta del server è "OK"
Gianluca Ghettini

2
@GianlucaGhettini perché, a volte il server è ciò che fornisce il servizio acquistato e non l'app inoltre, l'app potrebbe essere decodificata e quindi con qualche fatica il processo di verifica potrebbe essere violato.
Mohyaddin Alaoddin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.