サーバー側でAndroidアプリの購入を確認する方法(アプリ課金v3でのGoogle Play)


95

私はシンプルなアプリを持っています(アカウントでのユーザーログインが必要です)。ニュースコンテンツの増加など、有料ユーザー向けのプレミアム機能をいくつか提供しています。

ユーザーがサーバーデータベースでこのアイテムを購入したかどうかを記録する必要があります。ユーザーのデバイスにデータコンテンツを提供すると、ユーザーのステータスを確認して、有料ユーザーに別のコンテンツを提供できます。

私はGoogleから提供された公式のTrivialdriveサンプルを確認しましたが、サーバー側の検証用のサンプルコードは提供されていません。これが私の質問です。

  1. サンプルはアプリの公開鍵を内部で使用して購入を確認していることがわかりました。見た目は良くありません。確認プロセスをユーザーのログイン認証情報と組み合わせてサーバーに移動し、ユーザーの購入が完了したかどうかを確認してから、データベースを更新できます。
  2. また、クエリに使用できる購入APIもあります。必要なのは、ユーザーのPurchaseTokenをサーバーに渡すことです。

ユーザーの購入を確認し、データベースでユーザーのステータスをマークするためにどのような方法をとればよいかわかりません。

そして、ユーザーがgoogle playからこのアイテムを購入したという状況があるのではないかと思いますが、何らかの理由で、その間にアプリがサーバーへの検証を開始したときに、ネットワーク接続がダウンしているか、自分のサーバーがダウンしています、ユーザーはグーグルプレイでお金を支払いましたが、サーバーに購入を記録していませんか?どうすればいいですか、どうすればこの状況に対処できますか。


この質問からiosフラグを削除する必要があります。
グスタボゲバラ

回答:


159

あなたが探しているのは、ユーザーがアカウントでプレミアム機能を有効にしているかどうかを確認する方法なので、ここから始めます。

データベースにユーザーがプレミアム機能を持っているかどうかを示す何らかのフラグがあり、アカウント情報をリクエストするときにAPI応答ペイロードにそれを含めるようにしてください。このフラグは、「プレミアム機能」の主な権限になります。

ユーザーがアプリ内購入を行うとき、詳細(トークン、注文ID、製品ID)をクライアント(つまりアプリ)にローカルにキャッシュし、それをAPIに送信します。

次に、APIは検証のためにをGoogle Play Developer APIに送信するpurchaseToken必要があります

ここからいくつかのことが起こります:

  1. 領収書は有効です。APIは200 OKステータスコードでクライアントに応答します
  2. レシートが無効です。APIはクライアントに400 Bad Requestステータスコードで応答します
  3. Google Play APIがダウンし、APIが502 Bad Gatewayステータスコードで応答する

1.または2.(2xxまたは4xxステータスコード)の場合、APIが受け取ったことを示しているため、クライアントは購入の詳細のキャッシュを必要としません。

検証が成功すると(ケース1.)、premiumユーザーに対してフラグをtrueに設定する必要があります。

3.(5xxステータスコード)またはネットワークタイムアウトの場合、クライアントはAPIから2xxまたは4xxステータスコードを受信するまで試行を続ける必要があります。

要件に応じて、数秒待ってから再送信するか、アプリが再度起動されたとき、または購入の詳細がアプリのキャッシュに存在する場合にバックグラウンドから外れたときにAPIに詳細を送信することができます。

このアプローチは、ネットワークのタイムアウト、サーバーの利用不可などに対処する必要があります。

考慮すべきいくつかの質問があります。

購入直後はどうなりますか?アプリは、プレミアムコンテンツを提供する前に検証が成功するまで待機する必要がありますか、それとも一時的にアクセスを許可し、検証が失敗した場合はそれを削除する必要がありますか?

プレミアム機能への一時的なアクセスを許可すると、大多数のユーザーのプロセスがスムーズになりますが、APIがを検証している間、多数の不正なユーザーにもアクセスを許可することになりますpurchaseToken

別の言い方をすれば、購入は不正であることが証明されるまで有効です。有効であることが証明されるまで詐欺?

サブスクリプション期間が更新されたときに、ユーザーがまだ有効なサブスクリプションを持っているかどうかを識別するには、結果で返されたでpurchaseToken実行するの再検証をスケジュールする必要があります。expiryTimeMillis

場合はexpiryTimeMillis、過去に、あなたが設定できるpremiumフラグをfalseに。それが将来の場合は、新しいに合わせて再スケジュールしexpiryTimeMillisます。

最後に、ユーザーがプレミアムアクセス権を持っているかどうかを確認するには、アプリの起動時またはバックグラウンドから抜け出したときに、アプリがユーザーの詳細についてAPIにクエリする必要があります。


有料アプリの場合、Googleから領収書を入手するにはどうすればよいですか?
Merbin Joe

2
こんにちは!グーグルでサブスクリプション履歴にアクセスする方法はありませんか?PurchaseTokenを保存するときにアプリがクラッシュした場合に、すでに購入されたcubscriptionを使用していた事実が失われるのを防ぐにはどうすればよいですか?
scythargon 2017

2
私は同様の問題を抱えています...アプリがAPIにトークンを送信する代わりに、Googleデベロッパーサーバーに直接APIへのプッシュ通知を送信するように指示するための信頼性は高くありませんか?
ジャンルカゲッティーニ2017年

以下のためのサブスクリプション同じ古い購入・トークンを検証するために使用されている場合、Google PlayデベロッパーAPIはまだ、キャンセル後に200を返しますキャンセルされました。
セザールコブズ

したがって、サブスクリプションの場合、サーバーでの最初の呼び出しの後、購入トークンと製品IDを保存し、expiryTimeMillisが発生したときに他の検証呼び出しをスケジュールする(同じリクエストを再実行する)ことをお勧めします。それがサブスクリプションの有効性を確認する方法ですか?それを行う方法についてAndroidからのガイドラインはありますか?Appleは、WWDCのビデオを入手しましたが、その良い習慣をかなり明確に説明していますが、Playストアについてはあまりわかりません。
シャンカム

26

これに関するドキュメンテーションは、実際には重要なドキュメンテーションをほとんどリンクせず、見つけるのが非常に難しいまま、ほとんど重要ではないもので混乱し、奇妙に冗長です。これは、Java、Python、.Net、NodeJSなどのgoogle apiクライアントライブラリを実行できる最も人気のあるサーバープラットフォームでうまく機能するはずです。注:以下のように、Python APIクライアントのみをテストしました。

必要な手順:

  1. Google Play ConsoleのAPIアクセスリンクからAPIプロジェクトを作成します

  2. 新しいサービスアカウントを作成し、生成されたJSON秘密鍵を保存します。このファイルをサーバーに取り込む必要があります。

  3. Play Consoleのサービスアカウントセクションで[完了]を押して更新し、サービスアカウントへのアクセスを許可します

  4. https://developers.google.com/api-client-libraryから、サーバープラットフォーム用のGoogle APIクライアントライブラリを入手してください

  5. 特定のプラットフォームのクライアントライブラリを使用してサービスインターフェイスを構築し、購入確認の結果を直接読み取ります。

承認スコープを気にする必要ありません。カスタムリクエストの呼び出し、アクセストークンの更新などを行います。APIクライアントライブラリがすべてを処理します。次に、サブスクリプションを確認するためのpythonライブラリの使用例を示します。

まず、次のようにあなたのpipenvにgoogle apiクライアントをインストールします:

$ pipenv install google-api-python-client

次に、サービスアカウントを認証するための秘密鍵jsonファイルを使用して、APIクライアントの認証情報を設定できます。

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

これで、ライブラリを使用して、サブスクリプション購入または製品購入を直接確認できます。

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

Play開発者APIのプラットフォームサービスインターフェースのドキュメントは、簡単に見つけられるようにリンクされていませ。ここに私が見つけた人気のあるプラットフォームへのリンクがあります:

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


5
同意してください、ドキュメントは恐ろしいです... Firebase(Firestore)とCloud関数をバックエンドとしてこれを行う方法のアイデア
ジェフパジェット2018

Cloud関数がNodeJSにある場合、おそらく上記のNodeJSリンクを使用してAPIクライアントライブラリを機能させることができますか?
Dhiraj Gupta

17

PHPのGoogle APIクライアントライブラリを使用する完全な例:

  1. Marcの回答https://stackoverflow.com/a/35138885/1046909の説明に従って、Googleプロジェクトをセットアップし、サービスアカウントのGoogle Playにアクセスします

  2. ライブラリをインストールします:https : //developers.google.com/api-client-library/php/start/installation

  3. これで、次の方法で領収書を確認できます。

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

    その$購入後のインスタンスであるGoogle_Service_AndroidPublisher_SubscriptionPurchase

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

これが動作していない、私は得続ける(401)ログインが必要とsetAuthConfigは、サービスアカウントの資格情報をJSON受け入れるdoes notの
Raulnd

これは私のために働きましたputenv( 'GOOGLE_APPLICATION_CREDENTIALS = credentials.json'); $ client = new Google_Client(); $ client-> useApplicationDefaultCredentials(); $ client-> addScope( ' googleapis.com/auth/androidpublisher'); $ service = new Google_Service_AndroidPublisher($ client); $ purchase = $ service-> purchases_products-> get($ packageName、$ productId、$ token); var_dump($ purchase);
Raulnd 2017年

これはアプリ内課金の場合です。ユーザーがinappではなくPlayストアからアプリを購入するたびに、orderIdをデータベースに取得するにはどうすればよいですか?
Ankesh kumar Jaisansaria 2018

stackoverflow.com/questions/48662787/… この質問をご覧ください。この質問に対する答えを探しています。これにもアクティブな賞金があります
アンケシュクマールジャイサンサリア2018

@MingalevMEトークンの形式が無効でPHPに致命的なエラーが発生した場合、どうすればこのエラーをキャッチできますか?
alexx0186

12

Purchases.subscriptionsを使用して試すことができますサーバー側を取得します。これは、packageName、subscriptionId、およびトークンをパラメーターとして受け取り、承認が必要です

ユーザーのサブスクリプション購入が有効かどうかを確認し、有効期限を返します。

成功した場合、このメソッドはレスポンスの本文でPurchases.subscriptionsリソースを返します。


9
承認を機能させるために深刻な問題があります。

8
真剣に。一部のアプリにとって購入がいかに重要であるかについては、サポートとドキュメントは狂っています。これはサーバーで行う必要があることです:github.com/google/…。詳細:stackoverflow.com/questions/35127086/...
ユーザー

0

私はこの懸念に答えます

ネットワーク接続がダウンしている、または自分のサーバーがダウンしている、ユーザーがグーグルプレイでお金を支払ったが、サーバーに購入を記録しなかったのですか?どうすればいいですか、どうすればこの状況に対処できますか。

状況は次のとおりです。

ユーザーがGoogle Playサービスを使用して「abc」アイテムを購入した-> OKを返す->インターネット接続がないなどの理由でサーバーでの確認に失敗した。

解決策は次のとおりです。

クライアント側で、「Googleウォレット」ボタンを表示する前に、「abc」アイテムがすでに所有されているかどうかを確認します。

  • はいの場合、サーバーで再度確認します
  • いいえの場合は、[Googleウォレット]ボタンを表示します。

購入購入= 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
サーバーでの検証がアプリでの検証よりも安全である理由がわかりません。結局のところ、機能のロックを解除するのはアプリであり、サーバーの応答が「OK」であるかどうかをチェックするアプリのコードを削除または反転することは依然として可能です
Gianluca Ghettini

2
@GianlucaGhettiniは、サーバーがアプリ以外の購入したサービスを提供するものである場合があるため、アプリをリバースエンジニアリングして、検証プロセスをハッキングする可能性があるためです。
Mohyaddin Alaoddin 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.