Acquisti in-app per Android parte 5: convalida dell’acquisto lato server
Updated: Marzo 20, 2023
La convalida lato server (server-side) può aiutare a verificare l’autenticità degli acquisti. Il dispositivo effettua una richiesta ai server di Google per sapere se l’acquisto è effettivamente avvenuto e se è valido.
In questa guida, discuteremo di come configurare la convalida lato server per le applicazioni Android.
Perché convalidare gli acquisti (validate the purchases)
Va notato che la convalida lato server non è obbligatoria: gli acquisti in-app continueranno a funzionare anche senza. Tuttavia, presenta alcuni vantaggi significativi
- Analisi avanzata dei pagamenti, che è particolarmente importante per gli abbonamenti, poiché tutto ciò che accade dopo l’attivazione non viene elaborato dal dispositivo. Senza l’elaborazione degli acquisti sul lato server, non sarà possibile recuperare lo stato attuale dell’abbonamento e sapere se l’utente lo abbia rinnovato o lo abbia annullato, se ci siano problemi di pagamento e così via.
- La possibilità di verificare l’autenticità dell’acquisto. Sarai sicuro che la transazione non sia fraudolenta e che l’utente abbia effettivamente pagato il tuo prodotto.
- Abbonamenti a più piattaforme. Se puoi controllare lo stato dell’abbonamento dell’utente in tempo reale, puoi sincronizzarlo con altre piattaforme. Ad esempio, l’utente che ha acquistato l’abbonamento da un dispositivo iOS potrà utilizzarlo su Android, sul Web e su altre piattaforme.
- Possibilità di controllare l’accesso ai contenuti dal lato server, che protegge dagli utenti che cercano di accedere ai dati senza abbonamento, eseguendo semplicemente le richieste al server.
In base alla nostra esperienza, il primo vantaggio è già sufficiente per impostare l’elaborazione degli acquisti lato server.
Convalida dei pagamenti
Possiamo riassumere la convalida dei pagamenti su Android con questo schema:
Autenticazione per le richieste di Google Play Developer API
Per lavorare con Google Play Developer API, è necessario generare una chiave per firmare le richieste. Innanzitutto, dovrai collegare il tuo account Google Play Console (dove gestisci la tua app) al tuo account Google Cloud (dove genererai una chiave per la firma delle richieste). Una volta configurato il tutto, dovrai concedere all’utente i diritti di gestione degli acquisti. La descrizione di questo processo richiederebbe un articolo dedicato. Per fortuna, ne abbiamo già parlato in una guida passo passo, disponibile nella documentazione Adapty.
Facciamo notare che di solito è necessario attendere 24 ore o più dopo aver generato una chiave, affinché questa inizi a funzionare. Per evitarlo, basta aggiornare la descrizione di qualsiasi prodotto o abbonamento in-app, che attiverà la chiave immediatamente.
Per lavorare con Google Play Developer API, noi usiamo la libreria ufficiale google-api-python-client. Questa libreria è disponibile per la maggior parte dei linguaggi più diffusi e ti consiglio di usarla, perché supporta tutti i metodi di cui potresti aver bisogno.
Convalida per la transazione abbonamento
Diversamente dalla Convalida lato server iOS, In Android, la convalida degli abbonamenti e di altri prodotti viene effettuata con metodi diversi. Quindi, quando si convalida una transazione, è necessario sapere se si tratti di un prodotto o di un abbonamento. In pratica, ciò significa che dovrai trasferire questi dati dall’app mobile, oltre a mantenere il flag nel database nel caso in cui sia necessaria una nuova convalida del token.
La seconda differenza importante è che, mentre in Android ogni transazione ha un proprio token, tutte le transazioni iOS utilizzano un segreto condiviso (shared secret) specifico dell’app per memorizzare l’intera cronologia delle transazioni. Ciò significa che se si desidera poter ripristinare gli acquisti dell’utente in qualsiasi momento, è necessario memorizzare tutti i token di acquisto, invece di sceglierne uno singolo a caso.
Per convalidare l’abbonamento, dovrai richiamare il metodo purchases.subscriptions.get. In pratica, si tratta di una richiesta GET:
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}
Tutti i parametri sono obbligatori:
- packageName: Identificatore dell’app, ad esempio com.adapty.sample_app.
- subscriptionId: Identificatore dell’abbonamento da convalidare, ad esempio com.adapty.sample_app.weekly_sub.
- token: Token univoco della transazione. Appare una volta che l’acquisto è stato elaborato lato app mobile.
Per prima cosa, esaminiamo i messaggi di errore di cui è necessario occuparsi per assicurarsi che tutto funzioni come previsto:
- 400, Invalid grant: account not found: Questo messaggio di errore indica che la chiave di autenticazione della richiesta è stata generata in modo errato. Assicurati che i tuoi account siano collegati, che tu stia usando quello giusto con sufficienti autorizzazioni e che tutte le API necessarie siano attivate. Per una guida su come configurare il tutto, consulta la sezione seguente. Nota il suggerimento sull’aggiornamento della descrizione del prodotto.
- 400, The purchase token does not match the package name: Questo messaggio di errore viene solitamente riscontrato nelle transazioni fraudolente. Se lo vedi durante i test, assicurati di non utilizzare un token di acquisto che appartiene a un’altra app.
- 403, Quota exceeded for quota metric ‘Queries’ and limit ‘Queries per day’ of service ‘androidpublisher.googleapis.com’: Ciò significa che la quota giornaliera di richieste API di Google è stata superata. Per impostazione predefinita, è possibile eseguire fino a 200.000 richieste al giorno. Questa quota può essere aumentata, ma dovrebbe essere sufficiente per la maggior parte delle app. Se ti trovi di fronte a questo limite, ricontrolla la logica della tua app e assicurati che tutto sia corretto.
- 410, The subscription purchase is no longer available for query because it has been expired for too long: Questo messaggio di errore appare nelle transazioni in cui l’abbonamento è scaduto da più di 60 giorni. Non è un vero e proprio messaggio di errore e non dovrebbe essere elaborato come tale.
Transazione abbonamento
Se la convalida sarà riuscita, riceverai dati della transazione come risposta.
Dati della transazione (per un abbonamento):
{
"expiryTimeMillis": "1631116261362",
"paymentState": 1,
"acknowledgementState": 1,
"kind": "androidpublisher#subscriptionPurchase",
"orderId": "GPA.3382-9215-9042-70164",
"startTimeMillis": "1630504367892",
"autoRenewing": true,
"priceCurrencyCode": "USD",
"priceAmountMicros": "1990000",
"countryCode": "US",
"developerPayload": ""
}
Per capire se l’utente possa accedere alle opzioni premium offerte dall’app, ovvero se abbia un abbonamento attivo, è necessario:
- Controllare i parametri startTimeMillis e expiryTimeMillis. Il periodo corrente dovrebbe essere compreso tra i due.
- Inoltre, è necessario assicurarsi che il parametro paymentState non abbia valore “0”. Ciò significa che l’acquisto dell’abbonamento è ancora in corso, quindi non è necessario concedere all’utente l’accesso alle funzioni premium.
- Se la transazione ha la proprietà autoResumeTimeMillis , l’abbonamento viene messo in pausa. Ciò significa che all’utente non dovrà essere concesso l’accesso alla funzione premium prima della data specificata.
Vediamo le proprietà principali di una transazione di abbonamento:
- kind: Tipo di transazione Per l’abbonamento, ha sempre il valore androidpublisher#subscriptionPurchase. Con questo parametro, si può capire se si tratta di un abbonamento o di un prodotto e scegliere la logica di elaborazione di conseguenza.
- paymentState: Stato del pagamento Questa proprietà è assente per le transazioni scadute. I valori possibili sono:
0: L’acquisto non è ancora stato elaborato. In alcuni Paesi, l’utente può pagare l’abbonamento sul posto. In altre parole, l’utente avvia l’acquisto dell’abbonamento dal proprio dispositivo e lo paga presso un terminale nelle vicinanze. In generale, si tratta di un caso abbastanza raro, ma va comunque tenuto in considerazione.
1: L’abbonamento è stato acquistato.
2: L’abbonamento è nel periodo di prova.
3: L’abbonamento sarà ampliato o ridotto nel periodo successivo. Ciò significa che il piano d’abbonamento sta per cambiare.
- acknowledgementState: Stato di conferma dell’acquisto. È un parametro importante che riconosce se l’utente ha ricevuto l’accesso a ciò per cui ha pagato. Il valore “0” significa che non l’ha ricevuto, mentre “1” significa che l’ha ricevuto. Lo sviluppatore è responsabile della definizione di questo stato, che può essere effettuata sia sull’applicazione mobile che sul server. Se non confermi l’acquisto entro 3 giorni dalla sua effettuazione, verrà rimborsato automaticamente. Raccomando di implementare questa logica: una volta ricevuta una transazione che contiene acknowledgementState=0, il parametro viene modificato dal server. Di seguito, ti dico come fare.
- orderId: Identificativo univoco della transazione. Ogni acquisto o rinnovo dell’abbonamento avrà un proprio identificativo, utile per sapere se la transazione sia già stata elaborata in precedenza. Ogni identificativo di rinnovo avrà una prima metà costante, a cui vengono aggiunti due punti e il conteggio del rinnovo dell’abbonamento (che inizia con 0). Se, all’attivazione, l’abbonamento aveva l’identificatore GPA.3382-9215-9042-70164, il primo rinnovo sarà identificato come GPA.3382-9215-9042-70164..0, il secondo come GPA.3382-9215-9042-70164..1, ecc. In questo modo, è possibile creare catene di transazioni e tenere traccia del conteggio dei rinnovi.
- startTimeMillis: data di inizio dell’abbonamento
- expiryTimeMillis: data di scadenza dell’abbonamento
- autoRenewing: flag che indica se l’abbonamento debba essere rinnovato o meno nel periodo successivo.
- priceCurrencyCode: valuta di acquisto in un formato di tre lettere, ad esempio USD.
- priceAmountMicros: prezzo d’acquisto Per ottenere il valore del prezzo normale, dividi questo valore per 1000000. Questo significa che 1990000 in realtà vuol dire 1,99.
- countryCode: paese di acquisto in un formato di due lettere, ad esempio US.
- purchaseType: tipo d’acquisto. Nella maggior parte dei casi, questo valore non sarà presente. È comunque importante tenerne conto, perché aiuta a capire se l’acquisto sia stato effettuato in un ambiente Sandbox. I valori possibili sono:
0: L’acquisto è stato effettuato in un ambiente Sandbox, quindi non dovrebbe essere incluso nei dati di analisi..
1: L’acquisto è stato effettuato con un codice promozionale.
- autoResumeTimeMillis: Data di rinnovo dell’abbonamento È presente solo per gli abbonamenti precedentemente messi in pausa. Se questo parametro è presente, non è necessario concedere all’utente l’accesso alla funzione premium prima della data indicata.
- cancelReason: il motivo per cui l’abbonamento non sarà rinnovato. I valori possibili sono:
0: l’utente ha annullato il rinnovo automatico (subscription renewal) dell’abbonamento.
1: l’abbonamento è stato annullato dal sistema. Spesso, questa è la conseguenza di un problema di fatturazione (billing issue).
2: l’utente ha cambiato piano d’abbonamento.
3: lo sviluppatore ha annullato l’abbonamento.
- userCancellationTimeMillis: dati di annullamento del rinnovo dell’abbonamento (subscription renewal cancellation). È presente solo se il valore di cancelReason è a 0. L’abbonamento può essere ancora attivo – per esserne sicuro, vedi il valore del parametro expiryTimeMillis .
- cancelSurveyResult: oggetto che memorizza il motivo dell’annullamento dell’abbonamento, che sarà presente se l’utente avrà lasciato un feedback in merito.
- introductoryPriceInfo: oggetto che memorizza i dati relativi ai prezzi introduttivi (introductory price). Ad esempio, può trattarsi di un’offerta speciale di 1 mese con il 50% di sconto.
- promotionType: tipo di codice promozionale utilizzato per attivare l’abbonamento. I valori possibili sono:
0: Codice promo una tantum.
1: Codice promozionale personalizzato che può essere applicato da più clienti. Questi codici sono solitamente utilizzati per le partnership tra blogger.
- promotionCode: il tipo di codice promozionale che è stato utilizzato per attivare l’abbonamento. Questo parametro non è presente per i codici promozionali una tantum.
- priceChange: oggetto che memorizza i dati relativi alle future variazioni di prezzo, nonché l’eventuale consenso dell’utente.
Conferma dell’abbonamento
Come già detto in precedenza, nel caso in cui l’abbonamento non venga confermato entro 3 giorni dall’acquisto, verrà annullato e rimborsato automaticamente. Onestamente, non capisco la logica che sta alla base di questo fenomeno e non l’ho mai riscontrato in altri sistemi di elaborazione dei pagamenti, incluso quello iOS. Tuttavia, se si riceve una transazione contenente acknowledgementState=0, devi confermare l’abbonamento.
Per farlo, dovrai richiamare il metodo purchases.subscriptions.acknowledge. Questo metodo esegue una richiesta POST
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:acknowledge
I parametri sono gli stessi della convalida della richiesta (request validation). Se la richiesta va a buon fine, l’abbonamento viene confermato, il che significa che la somma sborsata non verrà persa.
Se il processo d’acquisto dell’abbonamento non è ancora stato completato, non è necessario confermarlo.
Cancellazione, revoca, rimborso e proroga del rinnovo dell’abbonamento (Subscription renewal cancellation, revocation, refund, and deferral)
Oltre alla convalida e alla conferma degli abbonamenti, l’API di Google Play Developer può essere utilizzata anche per altre operazioni di abbonamento. Va notato che questi casi sono piuttosto rari e, ad eccezione del rinnovo, sono supportati da Google Play Console. Li elencherò comunque, per darti una panoramica generale della portata delle soluzioni API. Tutte queste richieste hanno gli stessi parametri necessari per i metodi citati in precedenza, ossia, packageName, subscriptionId, e token.
- Annullamento del rinnovo. Il metodo purchases.subscriptions.cancel. Annulla il rinnovo automatico per l’abbonamento selezionato. Tuttavia, l’abbonamento sarà ancora disponibile per tutto il periodo di fatturazione in corso.
- Rimborso dell’abbonamento. Il metodo purchases.subscriptions.refund. Rimborsa l’abbonamento. Tuttavia, l’utente manterrà l’accesso all’abbonamento, che verrà rinnovato automaticamente nel periodo successivo. Nella maggior parte dei casi, quando si emette un rimborso si deve anche revocare l’abbonamento.
- Revoca dell’abbonamento Il metodo purchases.subscriptions.revoke. La revoca immediata dell’abbonamento comporta l’impossibilità per l’utente di accedere alle funzioni premium. L’abbonamento non sarà rinnovato. In genere, questo metodo viene richiamato insieme all’emissione di un rimborso.
- Proroga dell’acquisto dell’abbonamento. Il metodo purchases.subscriptions.defer. Prolunga l’abbonamento fino alla data specificata. Nella richiesta, specifica la data di scadenza dell’abbonamento e quella che desideri sostituire. Quest’ultima deve comportare un periodo di abbonamento più lungo del primo.
Product (not subscription) validation
La convalida del prodotto è simile alla convalida dell’abbonamento. Per eseguire la richiesta GET, bisognerà richiamare il metodo purchases.products.get.
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}
Tutti questi parametri sono già noti grazie agli esempi illustrati in precedenza.
Dati della transazione (per un prodotto):
{
"purchaseTimeMillis": "1630529397125",
"purchaseState": 0,
"consumptionState": 0,
"developerPayload": "",
"orderId": "GPA.3374-2691-3583-90384",
"acknowledgementState": 1,
"kind": "androidpublisher#productPurchase",
"regionCode": "RU"
}
Le transazioni prodotto includono un numero di proprietà molto inferiore rispetto alle transazioni abbonamento. Vediamone alcune importanti:
- kind: Tipo di transazione per il prodotto, ha sempre il valore androidpublisher#productPurchase. Con questo parametro, si può capire se si tratti di un abbonamento o di un prodotto e scegliere la logica di elaborazione di conseguenza.
- purchaseState: Stato del pagamento. Nota che i valori delle chiavi qui sono diversi da quelli del parametro per gli abbonamenti paymentState . I valori possibili sono:
0: l’acquisto è stato completato.
1: l’acquisto è stato annullato. Ciò significa che l’acquisto era in sospeso, ma l’utente non ha mai pagato.
2: l’acquisto è in sospeso. In alcuni paesi, l’utente può pagare l’abbonamento sul posto. In altre parole, l’utente avvia l’acquisto dell’abbonamento dal proprio dispositivo e lo paga presso un terminale nelle vicinanze. In generale, si tratta di un caso abbastanza raro, ma va comunque tenuto in considerazione.
- acknowledgementState: stato di conferma dell’acquisto. È un parametro importante che riconosce se l’utente ha ricevuto l’accesso a ciò per cui ha pagato. Il valore “0” significa che non l’ha ricevuto, mentre “1” significa che l’ha ricevuto. Lo sviluppatore è responsabile della definizione di questo stato, che può essere effettuata sia sull’applicazione mobile che sul server. Se non confermi l’acquisto entro 3 giorni dalla sua effettuazione, verrà rimborsato automaticamente. Raccomando di implementare questa logica: una volta ricevuta una transazione che contiene acknowledgementState=0, il parametro viene modificato dal server. Di seguito, ti dico come fare.
- consumptionState: Stato di consumo del prodotto. Questo è ciò che iOS chiama prodotto “consumabile”. Viene definito lato app mobile. Se il valore è “0”, significa che il prodotto non è stato consumato; se è ” 1”, è stato consumato. Se stai vendendo l’accesso a vita (lifetime access) alla tua app o a qualche specifica funzione premium, il prodotto non dovrebbe essere consumato, cioè dovrebbe essere nello stato 0. Se stai vendendo gettoni che l’utente può acquistare più volte, i prodotti devono essere consumati, cioè devono essere nello stato 1. consumptionState=0 significa che il prodotto può essere acquistato una sola volta, mentre consumptionState=1 significa che può essere acquistato più volte.
- orderId: identificativo univoco della transazione. Ogni acquisto o rinnovo dell’abbonamento avrà un proprio identificativo, utile per sapere se la transazione sia già stata elaborata in precedenza.
- purchaseTimeMillis: data d’acquisto.
- regionCode: paese di acquisto in un formato di due lettere, ad esempio US. Nota che il nome di questo parametro è diverso da quello degli abbonamenti, dove è chiamato countryCode.
- purchaseType: tipo d’acquisto. Nella maggior parte dei casi, questo valore non sarà presente. È comunque importante tenerne conto, perché aiuta a capire se l’acquisto sia stato effettuato in un ambiente Sandbox. I valori possibili sono:
0: l’acquisto è stato effettuato in un ambiente Sandbox, quindi non dovrebbe essere incluso nei dati di analisi.
1: l’acquisto è stato effettuato con un codice promozionale.
2: l’acquisto è stato concesso per un’azione mirata, ad esempio la visione di un annuncio in-app al posto del pagamento.
Come puoi vedere, la convalida del prodotto è abbastanza simile alla convalida dell’abbonamento. Ci sono però alcune cose da tenere in considerazione:
- Il prezzo non viene restituito, anche se sarebbe molto utile per l’analisi.
- I valori del parametro purchaseState sono significativamente diversi da quelli del parametro paymentState degli abbonamenti. Se questo non viene tenuto in considerazione, causerà dei bug.
- regionCode viene restituito, anche se per gli abbonamenti è chiamato countryCode .
Proprio come gli acquisti in abbonamento, anche gli acquisti di prodotti devono essere confermati. Per farlo, richiama il metodo purchases.products.acknowledge, che eseguirà una richiesta POST
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}:acknowledge
Se il processo d’acquisto non è ancora stato completato, non è necessario confermarlo.
Tracciabilità dei rimborsi per abbonamenti e prodotti
È impossibile avere un’analisi di alta qualità senza tener conto dei rimborsi. Purtroppo, i dati di rimborso non sono presenti nella transazione né vengono richiesti come evento (event) separato, come avviene in iOS. Per ricevere l’elenco delle transazioni rimborsate, è necessario richiamare purchases.voidedpurchases.list regolarmente, ad esempio una volta al giorno. Questo metodo eseguirà una richiesta GET:
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/voidedpurchases
In risposta alla richiesta, riceverai l’elenco di tutte le transazioni rimborsate. Io consiglio di ricercare le transazioni nel database in base al parametro orderId, piuttosto che con il parametro purchaseToken. Innanzitutto, richiederà meno tempo. In secondo luogo, tutti i rinnovi di abbonamento condivideranno lo stesso token e sarà sufficiente recuperare quello più recente.
Notifiche del server (server notifications) per le transazioni
Le notifiche del server (notifiche in tempo reale per gli sviluppatori) ti portano a conoscenza degli eventi che si sono verificati lato Google, sul tuo server e quasi in diretta. Una volta configurate, ti verranno notificati i nuovi acquisti, i rinnovi, i problemi di pagamento (payment issues), ecc. Questo può aiutarti a raccogliere analisi migliori e a semplificare la gestione dello stato degli abbonati.
Per iniziare a ricevere le notifiche del server, è necessario creare un argomento Pub/Sub di Google Cloud, che invierà le notifiche all’indirizzo desiderato. Questo argomento dovrebbe essere indicato nella sezione Impostazione monetizzazione di Google Play Console. Per una guida dettagliata completa delle schermate relative, vedi la documentazione Adapty.
Notifica del server:
{
"message": {
"data": "eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20uYWRhcHR5LnNhbXBsZV9hcHAiLCJldmVudFRpbWVNaWxsaXMiOiIxNjMwNTI5Mzk3MTI1Iiwic3Vic2NyaXB0aW9uTm90aWZpY2F0aW9uIjp7InZlcnNpb24iOiIxLjAiLCJub3RpZmljYXRpb25UeXBlIjo2LCJwdXJjaGFzZVRva2VuIjoiY2o3anAuQU8tSjFPelIxMjMiLCJzdWJzY3JpcHRpb25JZCI6ImNvbS5hZGFwdHkuc2FtcGxlX2FwcC53ZWVrbHlfc3ViIn19",
"messageId": "2829603729517390",
"message_id": "2829603729517390",
"publishTime": "2021-09-01T20:49:59.124Z",
"publish_time": "2021-08-04T20:49:59.124Z"
},
"subscription": "projects/935083/subscriptions/adapty-rtdn"
}
Qui ci interessa soprattutto la chiave data, che contiene i dati della transazione codificati con base64. La chiave messageId key può essere usata per la deduplicazione dei messaggi, in modo da non dover elaborare messaggi duplicati.
Ecco una transazione in una notifica del server:
{
"version": "1.0",
"packageName": "com.adapty.sample_app",
"eventTimeMillis": "1630529397125",
"subscriptionNotification": {
"version": "1.0",
"notificationType": 6,
"purchaseToken": "cj7jp.AO-J1OzR123",
"subscriptionId": "com.adapty.sample_app.weekly_sub"
}
}
La chiave packageName aiuta a capire a quale applicazione appartiene questo evento. La chiave subscriptionId indica quale abbonamento è interessato e purchaseToken consente di trovare la transazione specifica. Con gli abbonamenti, si cercherà sempre l’ultima transazione della catena di rinnovo, poiché è quella a cui apparterrà questo evento. La chiave notificationType contiene il tipo di evento. A mio parere, queste sono le chiavi più utili per gli abbonamenti:
- (2) SUBSCRIPTION_RENEWED: il rinnovo dell’abbonamento è andato a buon fine.
- (3) SUBSCRIPTION_CANCELED: l’utente ha annullato il rinnovo automatico dell’abbonamento. Se il rinnovo automatico è disattivato, dovrai cercare di recuperare l’utente come abbonato attivo.
- (5) SUBSCRIPTION_ON_HOLD, (6) SUBSCRIPTION_IN_GRACE_PERIOD: non è stato possibile rinnovare l’abbonamento a causa di un problema di pagamento. Dovrai avvisare l’utente, in modo che l’abbonamento non venga annullato automaticamente.
- (12) SUBSCRIPTION_REVOKED: l’abbonamento è stato revocato. Ciò significa che all’utente deve essere revocato l’accesso alle funzioni premium precedentemente garantite dall’abbonamento.
In prodotti (non abbonamenti), riceverai la chiave oneTimeProductNotification invece della subscriptionNotification. Conterrà anche la chiave sku invece della chiave subscriptionId. Inoltre, riceverai sempre e solo 2 tipi di eventi per i prodotti:
- (1) ONE_TIME_PRODUCT_PURCHASED: l’acquisto del prodotto andato a buon fine.
- (2) ONE_TIME_PRODUCT_CANCELED: l’acquisto del prodotto è stato annullato, poiché l’utente non l’ha pagato.
Conclusione
La convalida lato server aumenta il numero di analisi che potrai raccogliere per la tua app. Ciò rende più difficile ai truffatori l’accesso ai contenuti premium e può essere utilizzato per implementare abbonamenti su più piattaforme. Tuttavia, l’implementazione della convalida lato server può richiedere molto tempo, soprattutto se è necessaria un’elevata precisione dei dati. Per avere dati di alta qualità, è necessario tenere conto di una varietà di casi secondari, come l’aggiornamento dell’abbonamento, il crossgrade dell’abbonamento, i periodi di prova, le offerte promozionali (promo offer) e introduttive (intro offer), il periodo di tolleranza (grace period), i rimborsi, ecc. Inoltre, devi anche conoscere e tenere conto di tutti i minimi dettagli della policy, come ad esempio il fatto che Google addebita solo una commissione del 15% (anziché del 30%) sugli abbonamenti che vengono rinnovati per più di un anno.