So überprüfen Sie den Kauf für Android App auf der Serverseite (Google Play in App Billing v3)


95

Ich habe eine einfache App (benötigt Benutzer Login mit Konto). Ich biete einige Premium-Funktionen für bezahlte Benutzer, wie z. B. mehr Nachrichteninhalte.

Ich muss aufzeichnen, ob der Benutzer diesen Artikel in meiner Serverdatenbank gekauft hat. Wenn ich dem Benutzer Dateninhalte zur Verfügung stelle, kann ich den Status des Benutzers überprüfen und verschiedene Inhalte für bezahlte Benutzer bereitstellen.

Ich habe das offizielle Trivialdrive-Beispiel von Google überprüft. Es enthält keinen Beispielcode für die serverseitige Überprüfung. Hier sind meine Fragen.

  1. Ich habe festgestellt, dass das Beispiel den öffentlichen Schlüssel meiner App verwendet, um den Kauf zu überprüfen. Es sieht nicht gut aus. Ich denke, ich kann den Überprüfungsprozess einfach zusammen mit den Anmeldeinformationen des Benutzers auf meinen Server verschieben, um festzustellen, ob der Kauf des Benutzers abgeschlossen wurde, und dann die Datenbank aktualisieren.
  2. Außerdem gibt es eine Kauf-API, mit der ich abfragen kann. Ich muss das Kauf-Token des Benutzers an den Server übergeben.

Ich bin nicht sicher, wie ich den Kauf des Benutzers überprüfen und den Status des Benutzers in meiner Datenbank markieren soll, vielleicht beides?

Und ich befürchte, es gibt eine Situation, in der ein Nutzer diesen Artikel bei Google Play gekauft hat, aber aus irgendeinem Grund ist gerade in dieser Zeit, als meine App die Überprüfung meines Servers startete, die Netzwerkverbindung unterbrochen oder mein eigener Server ist ausgefallen . Benutzer hat gerade das Geld in Google Play bezahlt, aber ich habe den Kauf nicht auf meinem Server aufgezeichnet? Was soll ich tun, wie kann ich mit dieser Situation umgehen?


Sie sollten wahrscheinlich das ios-Flag aus dieser Frage entfernen.
Gustavo Guevara

Antworten:


158

Es klingt so, als ob Sie nach einer Möglichkeit suchen, um zu überprüfen, ob für den Benutzer Premium-Funktionen in seinem Konto aktiviert sind. Hier würde ich also beginnen.

Stellen Sie sicher, dass Ihre Datenbank eine Art Flag enthält, das angibt, ob der Benutzer über Premium-Funktionen verfügt, und fügen Sie diese in die API-Antwortnutzlast ein, wenn Sie Kontoinformationen anfordern. Dieses Flag ist Ihre Hauptautorität für "Premium-Funktionen".

Wenn ein Benutzer einen In-App-Kauf tätigt, speichern Sie die Details (Token, Bestell-ID und Produkt-ID) lokal auf dem Client (dh der App) und senden Sie sie an Ihre API.

Ihre API sollte diese dann zur Validierung purchaseTokenan die Google Play Developer API senden .

Von hier aus könnten einige Dinge passieren:

  1. Die Quittung ist gültig, Ihre API antwortet dem Client mit einem 200 Ok-Statuscode
  2. Die Quittung ist ungültig, Ihre API antwortet dem Client mit einem Statuscode für 400 Bad Request
  3. Die Google Play-API ist nicht verfügbar. Ihre API antwortet mit einem 502 Bad Gateway-Statuscode

Im Fall von 1. oder 2. (2xx- oder 4xx-Statuscodes) löscht Ihr Kunde den Cache mit Kaufdetails, da diese nicht mehr benötigt werden, da die API angegeben hat, dass sie empfangen wurden.

Nach einer erfolgreichen Validierung (Fall 1) sollten Sie das premiumFlag für den Benutzer auf true setzen.

Im Fall von 3. (5xx-Statuscode) oder einem Netzwerk-Timeout sollte der Client es so lange versuchen, bis er einen 2xx- oder 4xx-Statuscode von Ihrer API erhält.

Abhängig von Ihren Anforderungen können Sie einige Sekunden warten, bevor Sie erneut senden, oder die Details einfach an Ihre API senden, wenn die App erneut gestartet wird, oder den Hintergrund verlassen, wenn die Kaufdetails im App-Cache vorhanden sind.

Dieser Ansatz sollte Netzwerkzeitüberschreitungen, nicht verfügbare Server usw. berücksichtigen.

Es gibt jetzt einige Fragen, die Sie berücksichtigen müssen:

Was soll sofort nach dem Kauf passieren? Sollte die App warten, bis die Validierung erfolgreich ist, bevor sie Premium-Inhalte bereitstellt, oder sollte sie vorläufig Zugriff gewähren und diese entfernen, wenn die Validierung fehlschlägt?

Durch das Gewähren eines vorläufigen Zugriffs auf Premium-Funktionen wird der Prozess für die Mehrheit Ihrer Benutzer vereinfacht. Sie gewähren jedoch auch einer Reihe betrügerischer Benutzer Zugriff, während Ihre API das überprüft purchaseToken.

Anders ausgedrückt: Der Kauf ist gültig, bis sich herausstellt, dass er betrügerisch ist oder; betrügerisch bis nachweislich gültig?

Um festzustellen, ob der Benutzer zum Zeitpunkt der Verlängerung seines Abonnementzeitraums noch ein gültiges Abonnement hat, müssen Sie eine erneute Validierung für die purchaseTokenAusführung planen , die mit dem expiryTimeMillisim Ergebnis zurückgegebenen Abonnement ausgeführt werden soll .

Wenn das expiryTimeMillisin der Vergangenheit liegt, können Sie das premiumFlag auf false setzen. Wenn es in der Zukunft liegt, planen Sie es erneut für das neue expiryTimeMillis.

Um sicherzustellen, dass der Benutzer über Premium-Zugriff verfügt (oder nicht), sollte Ihre App Ihre API nach den Benutzerdetails beim Start der App oder bei Hintergrundinformationen abfragen.


Wie erhalte ich für eine kostenpflichtige App die Quittung von Google?
Merbin Joe

2
Hallo! Es gibt keine Möglichkeit, auf den Abonnementverlauf bei Google zuzugreifen. Wie kann verhindert werden, dass Fakten verloren gehen, die bereits gekaufte Abonnements verwendet haben, wenn die App zum Zeitpunkt des Speicherns von purchaseToken abstürzt?
Scythargon

2
Ich habe ein ähnliches Problem. Anstatt die App das Token an die API senden zu lassen, wäre es nicht zuverlässiger, den Google Developer Server anzuweisen, dies mit einer Push-Benachrichtigung direkt an meine API zu tun.
Gianluca Ghettini

Bei Abonnements , die gekündigt wurden, gibt die Google Play Developer API nach dem Kündigen immer noch 200 zurück, wenn dasselbe alte Kauf-Token für die Validierung verwendet wird.
Cezar Cobuz

Für ein Abonnement schlagen Sie also vor, dass wir nach dem ersten Aufruf auf dem Server das Kauftoken und die Produkt-ID speichern und einen weiteren Überprüfungsaufruf planen (dieselbe Anforderung erneut ausführen), wenn expiryTimeMillis auftritt. Sollen wir so die Gültigkeit des Abonnements überprüfen? Gibt es Richtlinien von Android, wie das geht? Apple hat ein WWDC-Video darüber, das die bewährte Vorgehensweise ziemlich klar erklärt, aber nicht viel über den Play Store herausfinden kann.
Schankam

26

Die Dokumentation dazu ist verwirrend und seltsam ausführlich mit den Dingen, die fast belanglos sind, während die tatsächlich wichtige Dokumentation fast unverbunden und sehr schwer zu finden ist. Dies sollte auf den meisten gängigen Serverplattformen funktionieren, auf denen die Google API-Clientbibliotheken ausgeführt werden können, darunter Java, Python, .Net und NodeJS. Hinweis: Ich habe nur den Python-API-Client wie unten gezeigt getestet.

Notwendige Schritte:

  1. Erstellen Sie ein API-Projekt über den API-Zugriffslink in Ihrer Google Play-Konsole

  2. Erstellen Sie ein neues Dienstkonto und speichern Sie den generierten privaten JSON-Schlüssel. Sie müssen diese Datei auf Ihren Server bringen.

  3. Klicken Sie im Abschnitt "Dienstkonto" der Play-Konsole auf "Fertig", um das Dienstkonto zu aktualisieren und anschließend Zugriff zu gewähren

  4. Unter https://developers.google.com/api-client-library erhalten Sie eine Google API-Clientbibliothek für Ihre Serverplattform

  5. Verwenden Sie die Clientbibliothek Ihrer Plattform, um eine Serviceschnittstelle zu erstellen und das Ergebnis Ihrer Kaufüberprüfung direkt zu lesen.

Sie müssen sich nicht um Autorisierungsbereiche kümmern, benutzerdefinierte Anfragen stellen, Zugriffstoken aktualisieren usw. Die API-Client-Bibliothek kümmert sich um alles. Hier ist ein Beispiel für die Verwendung der Python-Bibliothek, um ein Abonnement zu überprüfen:

Installieren Sie zunächst den Google API-Client wie folgt in Ihrem Pipenv:

$ pipenv install google-api-python-client

Anschließend können Sie API-Client-Anmeldeinformationen mithilfe der JSON-Datei mit privatem Schlüssel zur Authentifizierung des Dienstkontos einrichten.

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

Jetzt können Sie Abonnementkäufe oder Produktkäufe direkt über die Bibliothek überprüfen.

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

Die Dokumentation für die Plattform-Service-Oberfläche für die Play Developer API ist nicht leicht zu finden, für einige ist sie ausgesprochen schwer zu finden . Hier sind die Links zu den beliebten Plattformen, die ich gefunden habe:

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


5
Stimmen Sie zu, Dokumentation ist schrecklich ... Irgendwelche Ideen, wie dies mit Firebase (Firestore) und Cloud als Backend funktioniert?
Jeff Padgett

Wenn sich Ihre Cloud-Funktionen in NodeJS befinden, können Sie möglicherweise den obigen NodeJS-Link verwenden, um die API-Client-Bibliothek zum Laufen zu bringen.
Dhiraj Gupta

16

Vollständiges Beispiel für die Verwendung der Google API Client Library für PHP :

  1. Richten Sie Ihr Google-Projekt ein und greifen Sie auf Google Play für Ihr Dienstkonto zu, wie in Marc's Antwort hier https://stackoverflow.com/a/35138885/1046909 beschrieben .

  2. Installieren Sie die Bibliothek: https://developers.google.com/api-client-library/php/start/installation .

  3. Jetzt können Sie Ihre Quittung folgendermaßen überprüfen:

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

    Danach ist $ purchase eine Instanz von Google_Service_AndroidPublisher_SubscriptionPurchase

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

Dies funktioniert nicht, ich erhalte immer wieder (401) Login erforderlich und setAuthConfig akzeptiert die Anmeldeinformationen des Dienstkontos nicht json
Raulnd

Dieser hat bei mir funktioniert putenv ('GOOGLE_APPLICATION_CREDENTIALS = credentials.json'); $ client = neuer Google_Client (); $ client-> useApplicationDefaultCredentials (); $ client-> addScope (' googleapis.com/auth/androidpublisher' ); $ service = neuer Google_Service_AndroidPublisher ($ client); $ purchase = $ service-> purchase_products-> get ($ packageName, $ productId, $ token); var_dump ($ purchase);
Raulnd

Diese Sache ist im Falle einer inapp Abrechnung. Was ist, wenn ich orderId in meine Datenbank erhalten möchte, wenn der Benutzer meine App im Play Store statt inapp kauft?
Ankesh Kumar Jaisansaria

stackoverflow.com/questions/48662787/… Bitte beachten Sie diese Frage. Ich suche nach einer Antwort auf diese Frage. Dies hat auch aktive Prämie
Ankesh Kumar Jaisansaria

@MingalevME Was ist, wenn das Token-Format ungültig ist und PHP einen schwerwiegenden Fehler erhält? Wie kann ich diesen Fehler abfangen?
Alexx0186

12

Sie können versuchen, Purchases.subscriptions zu verwenden: Server-seitig. Paketparameter, Abonnement-ID und Token werden als Parameter verwendet und müssen autorisiert werden .

Überprüft, ob der Abonnementkauf eines Benutzers gültig ist, und gibt seine Ablaufzeit zurück.

Bei Erfolg gibt diese Methode eine Purchases.subscriptions-Ressource im Antworttext zurück.


9
Ich habe ernsthafte Probleme, damit die Autorisierung funktioniert.

8
Ernsthaft. In Bezug darauf, wie wichtig Käufe für einige Apps sind, ist der Support und die Dokumentation nicht korrekt. Dies müssen Sie auf dem Server tun: github.com/google/… . Weitere Infos hier: stackoverflow.com/questions/35127086/…
Benutzer

0

Ich antworte auf diese Besorgnis

Die Netzwerkverbindung ist unterbrochen oder mein eigener Server ist ausgefallen. Der Benutzer hat das Geld nur in Google Play bezahlt, aber ich habe den Kauf nicht auf meinem Server aufgezeichnet. Was soll ich tun, wie kann ich mit dieser Situation umgehen?

Die Situation ist:

Der Benutzer kauft "abc" über den Google Play-Dienst -> OK zurückgeben -> aus bestimmten Gründen, z. B. ohne Internetverbindung, keine Überprüfung beim Server.

Lösung ist:

Bevor Sie auf der Clientseite die Schaltfläche "Google Wallet" anzeigen, überprüfen Sie, ob das Element "abc" bereits im Besitz ist.

  • Wenn ja, überprüfen Sie dies erneut mit dem Server
  • Wenn nein, zeigen Sie die Schaltfläche "Google Wallet" an.

Kauf Kauf = 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
Ich verstehe nicht, warum die Validierung auf dem Server sicherer ist als die Validierung auf der App. Letztendlich ist es die App, die die Funktionen freischaltet, sodass es weiterhin möglich ist, den Code in der App zu entfernen oder zu invertieren, der prüft, ob die Serverantwort "OK" ist
Gianluca Ghettini

2
@GianlucaGhettini, weil manchmal der Server den gekauften Dienst bereitstellt, nicht die App, die App rückentwickelt werden könnte und dann mit etwas Mühe der Überprüfungsprozess gehackt werden könnte.
Mohyaddin Alaoddin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.