開発者コンソール

Appstore請求サービス対応用RVS本番環境のセットアップ

Appstore請求サービス対応用RVS本番環境のセットアップ

アプリを公開したら、アプリサーバーをセットアップして、RVS本番サーバーと通信するように設定できます。RVSは共有シークレットをホストしているため、セキュリティで保護されたサーバーから呼び出すことを推奨します。アプリからはRVSを呼び出さないでください。好みの言語とテクノロジーを使用して、アプリサーバーをセットアップしてください。サーバーでは、HTTPSなどのセキュリティで保護されたプロトコルを使用してRVSと通信する必要があります。サーバーでは、RVSに検証リクエストを送信し、受け取ったレスポンスを処理します。

クライアント側のセットアップ

クライアント側では、新しい購入が行われたときにAppstore請求サービス対応SDKのonPurchaseUpdated()メソッドが呼び出されます。次のようなAndroidサンプルコードでこれを処理します。

  1. onPurchaseUpdated()をオーバーライドして新しい購入をリッスンします。
  2. 購入リストがnullでなければ、購入トークンをアプリサーバーに渡して各購入を検証します。
  3. 購入が有効な場合はアイテムを付与し、そうでない場合は検証エラーをログに記録します。
private void processPurchaseList(List<Purchase> purchases, List<String> skusToUpdate) {

    if (null != purchases) {
        for (final Purchase purchase : purchases) {
            // レシート検証サービスを使用してレシートを検証します。
            final String purchaseToken = purchase.getPurchaseToken();
            // 購入トークンをセキュリティで保護されたバックエンドに送信して検証します。
            if(verifyInAppItemReceipt(purchaseToken, productType, packageName)) {
                // 購入を処理し、アイテムを付与します。
            } else {
                Log.d("購入が無効です")
            }
        }
    }
}

@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
    
    switch (billingResult.getResponseCode()) {
    
        case BillingClient.BillingResponseCode.OK:
            if(list != null) {
                processPurchaseList(list, null);
                return;
            }
            else {
                Log.d(TAG, "OKのレスポンスからnullの購入リストが返されました");
            }
            break;
        case BillingClient.BillingResponseCode.USER_CANCELED:
        case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED:
        case BillingClient.BillingResponseCode.DEVELOPER_ERROR:
            // 状況に応じた処理を行います。
            break;
        default:
            // デフォルトの処理を行います。
            break;
    }
}

サーバー側のセットアップ

以下で紹介しているのは、汎用Javaサーバー用のサンプルコードです。このコードでは、purchases.products.getおよびpurchases.subscriptionsv2.get APIを呼び出して、次のタスクを実行します。

  1. 適切な開発者情報とトランザクション情報を含んだURL文字列を作成します。
  2. Amazon RVSサーバーに接続し、トランザクションURLを渡します。
  3. Amazon RVSサーバーからレスポンスを取得します。
  4. レスポンスをアプリに渡します。
// 非消費型アイテムまたは消費型アイテムのレシートの検証
public static void verifyInAppItemReceipt(final String developerSecret, final String packageName, final String token) {

    // purchases.products.get APIを呼び出してIAPアイテムの購入を検証します。
    String url = "https://appstore-sdk.amazon.com/version/1.0/" + 
    "developer/" + developerSecret + "/applications/" + packageName + "/purchases/subscriptionsv2/tokens/" + token

    JSONObject responseJson = verifyReceipt(url);

    JSONObject canceledStateContext = responseJson.getJSONObject("CanceledStateContext");
    String purchaseToken = responseJson.getString("purchaseToken");
    long purchaseTimeMillis = responseJson.getString("purchaseTimeMillis");
    long cancelDate = responseJson.optLong("cancelDate");
    boolean testTransaction = responseJson.optBoolean("testTransaction");
}

// 定期購入型アイテムのレシートの検証
public static void verifySubscriptionReceipt(final String developerSecret, final String packageName, final String productId, final String token) {
    
    // purchases.subscriptionsv2.get APIを呼び出して定期購入型アイテムの購入を検証します。
    String url = "https://appstore-sdk.amazon.com/version/1.0/" + 
    "developer/" + developerSecret + "/applications/" + packageName + "/purchases/products/" + productId + "/tokens/" + token

    JSONObject responseJson = verifyReceipt(url);

    String purchaseToken = responseJson.getString("purchaseToken");
    String productType = responseJson.getString("productType");
    String productId = responseJson.getString("productId");
    long purchaseTimeMillis = responseJson.getString("purchaseTimeMillis");
    long cancelDate = responseJson.optLong("cancelDate");
    boolean testTransaction = responseJson.optBoolean("testTransaction");
}

private static void verifyReceipt(final String url) {
    System.out.println("レシート検証を開始します");

    System.out.println("Amazonレシート検証URL:" + url);


    JSONObject responseJson = null;
    try {
        System.out.println("Amazon RVSへのHTTP接続を開きます");

        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();

        int responseCode = con.getResponseCode();

        System.out.println("Amazon RVSレスポンスコード:" + responseCode);

        switch (responseCode)
        {
            case 400:
                System.out.println("Amazon RVSエラー: 無効な購入トークンまたはproductId");
                // レスポンスデータをローカルで処理します。
                // アプリに応答します。
                break;

            case 401:
                System.out.println("Amazon RVSエラー: 無効なdeveloperSecret");
                // レスポンスデータをローカルで処理します。
                // アプリに応答します。
                break;

            case 404:
                System.out.println("Amazon RVSエラー: 無効なpackageName");
                // レスポンスデータをローカルで処理します。
                // アプリに応答します。
                break;

            case 500:
                System.out.println("Amazon RVSエラー: 内部サーバーエラー");
                // レスポンスデータをローカルで処理します。
                // アプリに応答します。
                break;

            case 200:

                // Amazon RVSレスポンスを取得します。
                BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()));

                String inputLine;
                StringBuffer response = new StringBuffer();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // Amazon RVSレスポンスをログに記録します。
                System.out.println("Amazon RVSレスポンス:" + response.toString()());

                // RVSレスポンスのJSONObjectを作成します。
                JSONObject responseJson = new JSONObject(response.toString());

                // RVSレスポンスを解析します。
                responseJson = new JSONObject(response.toString());
                break;

            default:
                System.out.println("Amazon RVSエラー: 未定義のAmazon RVSレスポンスコード");
                // レスポンスデータをローカルで処理します。
                // アプリに応答します。
                break;
        }

    } catch (MalformedURLException e) {

        // ベストプラクティスとして、次のロジックをログ記録のロジックに置き換えることをお勧めします。
        System.out.println("Amazon RVS MalformedURLException");
        e.printStackTrace();
        // レスポンスデータをローカルで処理します。
        // アプリに応答します。
    } catch (IOException e) {

        // ベストプラクティスとして、次のロジックをログ記録のロジックに置き換えることをお勧めします。
        System.out.println("Amazon RVS IOException");
        e.printStackTrace();
        // レスポンスデータをローカルで処理します。
        // アプリに応答します。
    }

    return responseJson;
}

Last updated: 2024年5月22日