非消費型デジタル トランザクションの構築(Dialogflow)

このガイドでは、ユーザーが非消費型デジタル商品を購入できるように、会話アクションにデジタル トランザクションを追加する方法について説明します。

重要な用語: 非消費型デジタル アイテムとは、アクションや Android アプリでの追加コンテンツへの有料アクセスなど、1 回しか購入できない最小管理単位(SKU)のことです。このタイプの商品は、購入、使用、再購入が可能な消費型デジタル アイテムとは異なります。

消費不可の 1 回限りのアイテムについて詳しくは、Android のドキュメントで 1 回限りのアイテム固有の機能に関する説明をご覧ください。

制限と審査のガイドライン

トランザクションを含むアクションには、追加のポリシーが適用されます。Google がトランザクションを含むアクションの審査には数週間かかることがあります。リリース スケジュールを計画するときは、この時間を考慮してください。審査プロセスを容易にするため、審査のためにアクションを送信する前に、取引に関するポリシーとガイドラインに準拠していることを確認してください。

デジタル商品を販売するアクションは、次の国でのみデプロイできます。

  • オーストラリア
  • ブラジル
  • カナダ
  • インドネシア
  • 日本
  • メキシコ
  • ロシア
  • シンガポール
  • タイ
  • トルコ
  • 英国
  • 米国

取引の流れ

このガイドでは、デジタル商品の取引フローで発生する各開発ステップの概要を説明します。アクションは、デジタル商品の取引を処理する場合、次のフローを使用します。

  1. デジタル購入 API クライアントを設定する: アクションは Digital Purchases API を使用して Google Play 広告枠と通信し、取引を行います。アクションはなんらかの処理を行う前に、デジタル購入 API と通信するためのサービスキーを持つ JWT クライアントを作成します。
  2. 情報を収集する: アクションは、取引の準備をするために、ユーザーと Google Play インベントリに関する基本情報を収集します。
    1. 取引要件を検証する: アクションは、購入フローの開始時にデジタル取引要件ヘルパーを使用して、ユーザーが取引できることを確認します。
    2. 利用可能な在庫を収集する: アクションは Google Play の在庫をチェックし、現在購入可能なアイテムを特定します。
  3. 注文を作成する: アクションは、ユーザーが購入可能なデジタル商品を選択できるようにします。
  4. 購入を完了する: アクションは Digital Purchases API を使用して、Google Play ストアへのユーザーの選択に基づいて購入を開始します。
  5. 結果を処理する: アクションは取引のステータス コードを受け取り、購入が正常に完了したこと(または追加の手順が必要)をユーザーに通知します。

前提条件

デジタル取引をアクションに組み込むには、次の前提条件を満たす必要があります。

  • Google Play のデベロッパー アカウント販売アカウントGoogle Play Console でデジタル商品を管理します。

  • Google Search Console で確認されたウェブドメイン。このドメインは、一般公開されているウェブサイトに関連付ける必要はありません。Google が参照する必要があるのはウェブドメインだけです。

  • Google Play Console で com.android.vending.BILLING 権限を付与された Android アプリ。デジタル商品は、Google Play Console でこのアプリに関連付けられた「アプリ内購入」になります。

    また、このアプリを使用して Google Play Console でリリースを作成する必要がありますが、リリースを公開したくない場合は、クローズド アルファ版リリースを作成できます。

    Android アプリをまだお持ちでない場合は、Android アプリの関連付けの手順に沿って操作してください。

  • Google Play Console の 1 つ以上の管理対象アイテム。アクションと一緒に販売するデジタル商品です。Android アプリの前提条件を設定するまで、Google Play Console で管理対象アイテムを作成することはできません。

    管理対象アイテムがない場合は、デジタル アイテムの作成手順に沿って進めてください。

Android アプリを関連付ける

請求に関する権限を持つ Android アプリが現在 Google Play Console にない場合は、次の手順を行います。

  1. Android Studio または任意の Android IDE で、新しいプロジェクトを作成します。プロジェクト設定プロンプトでオプションを選択して、非常に基本的なアプリを作成します。
  2. プロジェクトにパッケージ名を付けます(例: com.mycompany.myapp)。com.example を含むパッケージは Google Play Console にアップロードできないため、この名前をデフォルトのままにしないでください。
  3. アプリの AndroidManifest.xml ファイルを開きます。
  4. manifest 要素内に次のコード行を追加します。

    <uses-permission android:name="com.android.vending.BILLING" />

    AndroidManifest.xml ファイルは次のコードブロックのようになります。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.mycompany.myapp">
        <uses-permission android:name="com.android.vending.BILLING" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme" />
    </manifest>
    
  5. 署名済み APK としてアプリをビルドします。Android Studio で次の操作を行います。

    1. [Build]、[Generate Signed Bundle / APK] の順に移動します。
    2. [次へ] をクリックします。
    3. [Key store path] で、[Create new] をクリックします。
    4. 各フィールドに入力し、[OK] をクリックします。[キーストアのパスワード] と [鍵のパスワード] は後で使用するため、安全な場所に保管してください。
    5. [次へ] をクリックします。
    6. [release] を選択します。
    7. [V1(JAR Signature)] を選択します。
    8. [Finish] をクリックします。
    9. 数秒後、Android Studio が app-release.apk ファイルを生成します。 後で使用するために、このファイルを見つけてください。
  6. Google Play Console で、新しいアプリを作成します。

  7. [アプリのリリース] に移動します。

  8. [クローズド トラック] で [管理]、[アルファ版] の順に移動します。

  9. [リリースの作成] ボタンをクリックします。

  10. [Google が署名鍵の管理と保護を行う] で、署名鍵情報を入力します。

  11. APK ファイルをアップロードします。

  12. [保存] をクリックします。

デジタル アイテムを作成する

現在 Google Play Console にデジタル商品がない場合は、次の手順を行います。

  1. Google Play Console で、[アプリ内アイテム]、[管理対象アイテム] の順に移動します。警告が表示された場合は、前述の手順に沿って Android アプリを作成するか、リンクをクリックして販売者プロフィールを作成します。
  2. [管理対象アイテムを作成] をクリックします。
  3. デジタル商品の項目を入力します。プロダクト ID は、アクションからこの商品を参照する際に使用します。
  4. [保存] をクリックします。
  5. 販売する商品ごとにステップ 2 ~ 4 を繰り返します。

Google Play Console に表示される非消費型アイテムの例

Actions プロジェクトを準備する

Google Play Console でデジタル商品をセットアップしたら、デジタル トランザクションを有効にし、Actions プロジェクトを Play アプリに関連付ける必要があります。

Actions プロジェクトでデジタル商品の取引を有効にする手順は次のとおりです。

  1. Actions Console でプロジェクトを開くか、新しいプロジェクトを作成します。
  2. [Deploy]、[Directory information] の順に移動します。
  3. [その他の情報] と [トランザクション] で、[アクションで Digital Purchase API を使用してデジタル商品のトランザクションを実行します] で [はい] チェックボックスをオンにします。
  4. [保存] をクリックします。

デジタル商品の API キーを作成する

Digital Goods API にリクエストを送信するには、Actions Console プロジェクトに関連付けられた JSON サービス アカウント キーをダウンロードする必要があります。

サービス アカウント キーを取得する手順は次のとおりです。

  1. Actions Console で、右上のその他アイコンをクリックし、[プロジェクト設定] をクリックします。
  2. アクションのプロジェクト ID を確認します。
  3. 次のリンクにアクセスします。「<project_id>」は実際のプロジェクト ID に置き換えてください。 https://console.developers.google.com/apis/credentials?project=project_id
  4. メイン ナビゲーションで [認証情報] に移動します。
  5. 表示されたページで [認証情報を作成]、[サービス アカウント キー] の順にクリックします。
  6. [サービス アカウント] に移動し、[新しいサービス アカウント] をクリックします。
  7. サービス アカウントに「digitaltransactions」などの名前を付けます。
  8. [作成] をクリックします。
  9. [ロール] を [プロジェクト] > [オーナー] に設定します。
  10. [Continue](続行)をクリックします。
  11. [キーを作成] をクリックします。
  12. キータイプとして [JSON] を選択します。
  13. [キーを作成] をクリックし、JSON サービス アカウント キーをダウンロードします。

このサービス アカウント キーは安全な場所に保管してください。このキーをフルフィルメントで使用して、Digital Purchases API のクライアントを作成します。

Play 広告枠に接続する

Actions プロジェクトからデジタル商品にアクセスするには、ウェブドメインとアプリを接続プロパティとしてプロジェクトに関連付けます。

注: プロパティの確認が完了するまで、接続手順が完了するまでに最長で 1 週間かかることがあります。その期間を過ぎてもウェブサイトまたはアプリがリンクされていない場合は、サポートにお問い合わせください。

Google Play Console のウェブドメインとアプリを Actions プロジェクトに接続する手順は次のとおりです。

  1. Actions Console で、[Deploy]、[Brand verification] の順に移動します。
  2. プロパティを接続していない場合は、まずウェブサイトを接続します。

    1. ウェブ プロパティ(</>)ボタンをクリックします。
    2. ウェブドメインの URL を入力し、[接続] をクリックします。

    Google Search Console でウェブドメインの所有権が確認された個人に、詳しい手順が記載されたメールを送信します。このメールの受信者がこれらの手順を完了すると、[ブランドの確認] の下にウェブサイトが表示されます。

  3. 1 つ以上のウェブサイトを接続したら、次の手順で Android アプリを接続します。

    1. Actions Console で、[Deploy]、[Brand verification] の順に移動します。
    2. [Connect App](アプリを接続)をクリックします。
    3. 表示されたページで、手順に沿って Google Play Console でウェブドメインを確認します。デジタル商品が含まれている Play アプリを選択し、[ブランドの確認] ページに表示されているとおりにウェブドメインの URL を入力します。

      ここでも、Google からドメインの確認済み所有者に確認メールが送信されます。オーナーが確認を承認すると、Play アプリが [ブランドの確認] に表示されます。

    4. [Access Play purchases](Play での購入にアクセス)を有効にします。

Actions プロジェクトに接続されているウェブサイトとアプリを示す画像。

購入フローを構築する

Actions プロジェクトとデジタル商品在庫を用意したら、会話フルフィルメント Webhook でデジタル商品の購入フローを構築します。

1. Digital Purchases API クライアントを設定する

会話フルフィルメント Webhook で、サービス アカウントの JSON キーと https://www.googleapis.com/auth/actions.purchases.digital スコープを使用して JWT クライアントを作成します。

次の Node.js コードは、Digital Purchases API の JWT クライアントを作成します。

  const serviceAccount = {'my-file.json'};
  const request = require('request');
  const {google} = require('googleapis');

  const jwtClient = new google.auth.JWT(
    serviceAccount.client_email, null, serviceAccount.private_key,
    ['https://www.googleapis.com/auth/actions.purchases.digital'],
    null
  );

2. 情報を収集する

ユーザーが購入を行う前に、アクションはユーザーの購入可否と在庫から購入可能な商品に関する情報を収集します。

2. a. 取引要件を検証する

購入オプションを提供する前に、ユーザーのアカウントが取引を行う準備ができていることを確認することをおすすめします。この手順では、ユーザーがお支払い方法を構成していること、ユーザーがデジタル取引がサポートされている言語 / 地域にいることを確認します。トランザクション フローの開始時に、DIGITAL_PURCHASE_CHECK ヘルパーを使用して、アシスタントでユーザーのトランザクション構成を検証します。

次の Node.js コードは、会話の開始時に DIGITAL_PURCHASE_CHECK を使用します。

app.intent('Default Welcome Intent', async (conv, { SKU }) => {
  // Immediately invoke digital purchase check intent to confirm
  // purchase eligibility.
  conv.ask(new DigitalPurchaseCheck());
});

この確認の結果を、会話引数で DIGITAL_PURCHASE_CHECK_RESULT として見つけます。この結果に基づいて、取引フローを続行するか、取引フローから離れて、Google Pay の構成を確認するようにユーザーに促します。

次の Node.js コードは、要件チェックの結果を処理します。

app.intent('Digital Purchase Check', async (conv) => {
  const arg = conv.arguments.get('DIGITAL_PURCHASE_CHECK_RESULT');
  if (!arg || !arg.resultType) {
    conv.close('Digital Purchase check failed. Please check logs.');
    return;
  }
  // User does not meet necessary conditions for completing a digital purchase
  if (arg.resultType === 'CANNOT_PURCHASE' || arg.resultType === 'RESULT_TYPE_UNSPECIFIED') {
    conv.close(`It looks like you aren't able to make digital purchases. Please check your Google Pay configuration and try again.`);
    return;
  }
  conv.ask('Welcome to the Digital Goods Sample. Would you like to see what I have for sale?');
});

2. b. 利用可能なインベントリを収集する

Digital Purchases API を使用して、現在利用可能な Google Play ストアの在庫をリクエストし、商品ごとの JSON オブジェクトの配列を作成します。この配列を後で参照して、購入可能なオプションをユーザーに示します。

各デジタル商品は、JSON 形式の SKU として表されます。次の Node.js コードは、各 SKU で想定される形式を示しています。

body = {
  skus: [
    skuId: {
      skuType: one of "APP" or "UNSPECIFIED"
      id: string,
      packageName: string
    }
    formattedPrice: string,
    title: string,
    description: string
  ]
}

https://actions.googleapis.com/v3/packages/{packageName}/skus:batchGet エンドポイントに POST リクエストを送信し、{packageName} は Google Play Console のアプリのパッケージ名(com.myapp.digitalgoods など)で、その結果を SKU オブジェクトの配列形式にします。

結果の配列で特定のデジタル商品のみを取得するには、body.ids で購入可能にするデジタル商品の商品 ID をリストします(Google Play Console の各アプリ内アイテムの下に表示されます)。

次の Node.js コードは、Digital purchases API に購入可能な商品のリストをリクエストし、その結果を SKU の配列としてフォーマットします。

return jwtClient.authorize((err, tokens) => {
    if (err) {
      throw new Error(`Auth error: ${err}`);
    }

    const packageName = 'com.example.projectname';

    request.post(`https://actions.googleapis.com/v3/packages/${packageName}/skus:batchGet`, {
      'auth': {
        'bearer': tokens.access_token,
      },
      'json': true,
      'body': {
        'conversationId': conversationId,
        'skuType': 'APP',
        // This request is filtered to only retrieve SKUs for the following product IDs
        'ids': ['nonconsumable.1']
      },
    }, (err, httpResponse, body) => {
      if (err) {
        throw new Error(`API request error: ${err}`);
      }
      console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`);
      console.log(JSON.stringify(body));
    });
  });
});

3. 注文を作成する

ユーザーがデジタル購入を開始するには、購入可能なデジタル商品のリストを提示します。さまざまなリッチ レスポンス タイプを使用して在庫を表し、ユーザーに選択を求めるプロンプトを表示できます。

次の Node.js コードは、SKU オブジェクトのインベントリ配列を読み取り、それぞれに 1 つのリストアイテムを含むリスト レスポンスを作成します。

skus.forEach((sku) => {
  const key = `${sku.skuId.skuType},${sku.skuId.id}`
  list.items[key] = {
    title: sku.title,
    description: `${sku.description} | ${sku.formattedPrice}`,
  };
});

4. 購入を完了する

購入を完了するには、ユーザーが選択したアイテムで COMPLETE_PURCHASE ヘルパー インテントを使用します。

次の Node.js コードは、リスト レスポンスからのユーザーの SKU 選択を処理し、その情報を使用して COMPLETE_PURCHASE インテントをリクエストします。

app.intent('Send Purchase', (conv, params, option) => {
  let [skuType, id] = option.split(',');

  conv.ask(new CompletePurchase({
    skuId: {
      skuType: skuType,
      id: id,
      packageName: <PACKAGE_NAME>,
    },
  }));
});

5. 結果を処理する

購入が完了すると、actions_intent_COMPLETE_PURCHASE Dialogflow イベント(または actions.intent.COMPLETE_PURCHASE Actions SDK インテント)がトリガーされ、COMPLETE_PURCHASE_VALUE 引数に結果が説明されます。このイベントによってトリガーされ、結果をユーザーに伝えるインテントを作成します。

次のような購入結果を処理します。

  • PURCHASE_STATUS_OK: 購入が成功しました。この時点でトランザクションが完了しているため、トランザクション フローを終了し、会話に戻ります。
  • PURCHASE_STATUS_ALREADY_OWNED: ユーザーがすでにそのアイテムを所有しているため、取引に失敗しました。このエラーは、ユーザーの過去の購入を確認し、表示されているアイテムを調整して、すでに所有しているアイテムを再購入できないようにします。
  • PURCHASE_STATUS_ITEM_UNAVAILABLE: リクエストされたアイテムは利用できないため、トランザクションに失敗しました。購入時期が近づいたら、利用可能な SKU を確認して、このエラーを回避してください。
  • PURCHASE_STATUS_ITEM_CHANGE_REQUESTED: ユーザーが別のものを購入するため、取引が失敗しました。ユーザーがすぐに別の決定を下せるように、注文の作成を再度プロンプトします。
  • PURCHASE_STATUS_USER_CANCELLED: ユーザーが購入フローをキャンセルしたため、取引に失敗しました。ユーザーが途中でフローを終了したため、取引を再試行するか、完全に取引を終了するかをユーザーに確認します。
  • PURCHASE_STATUS_ERROR: 原因不明な理由で取引が失敗しました。取引に失敗したことをユーザーに伝え、再試行するかどうかを確認します。
  • PURCHASE_STATUS_UNSPECIFIED: 原因不明な理由で取引が失敗しました。現在のステータスも不明です。このエラー ステータスを処理するには、取引が失敗したことをユーザーに伝え、再試行するかどうかを確認します。

次の Node.js コードは、COMPLETE_PURCHASE_VALUE 引数を読み取り、各結果を処理します。

app.intent('Purchase Result', (conv) => {
  const arg = conv.arguments.get('COMPLETE_PURCHASE_VALUE');
  console.log('User Decision: ' + JSON.stringify(arg));
  if (!arg || !arg.purchaseStatus) {
    conv.close('Purchase failed. Please check logs.');
    return;
  }
  if (arg.purchaseStatus === 'PURCHASE_STATUS_OK') {
    conv.close(`Purchase completed! You're all set!`);
  } else if (arg.purchaseStatus === 'PURCHASE_STATUS_ALREADY_OWNED') {
    conv.close('Purchase failed. You already own this item.');
  } else if (arg.purchaseStatus === 'PURCHASE_STATUS_ITEM_UNAVAILABLE') {
    conv.close('Purchase failed. Item is not available.');
  } else if (arg.purchaseStatus === 'PURCHASE_STATUS_ITEM_CHANGE_REQUESTED') {
    // Reprompt with your item selection dialog
  }  else {
    conv.close('Purchase Failed:' + arg.purchaseStatus);
  }
});

ユーザーの購入情報を反映

ユーザーがアクションにクエリを実行すると、リクエスト JSON の user オブジェクトには購入のリストが含まれます。この情報を確認し、ユーザーが購入したコンテンツに基づいてアクションの応答を変更します。

次のサンプルコードは、リクエストの user オブジェクトを示しています。このオブジェクトには、com.digitalgoods.application パッケージに対して行った過去のアプリ内購入の packageEntitlements が含まれています。

  "user": {
    "userId": "xxxx",
    "locale": "en-US",
    "lastSeen": "2018-02-09T01:49:23Z",
    "packageEntitlements": [
      {
        "packageName": "com.digitalgoods.application",
        "entitlements": [
          {
            "sku": "non-consumable.1",
            "skuType": "APP"
          }
          {
            "sku": "consumable.2",
            "skuType": "APP"
          }
        ]
      },
      {
        "packageName": "com.digitalgoods.application",
        "entitlements": [
          {
            "sku": "annual.subscription",
            "skuType": "SUBSCRIPTION",
            "inAppDetails": {
              "inAppPurchaseData": {
                "autoRenewing": true,
                "purchaseState": 0,
                "productId": "annual.subscription",
                "purchaseToken": "12345",
                "developerPayload": "HSUSER_IW82",
                "packageName": "com.digitalgoods.application",
                "orderId": "GPA.233.2.32.3300783",
                "purchaseTime": 1517385876421
              },
              "inAppDataSignature": "V+Q=="
            }
          }
        ]
      }
    ]
  },
  "conversation": {
    "conversationId": "1518141160297",
    "type": "NEW"
  },
  "inputs": [
    {
      "intent": "actions.intent.MAIN",
      "rawInputs": [
        {
          "inputType": "VOICE",
          "query": "Talk to My Test App"
        }
      ]
    }
  ],
  ...
}