建構非消耗性數位交易

本指南說明如何在數位對話中加入數位交易,讓使用者可以購買非消耗性數位商品。

重要字詞:非消耗性數位商品是只能購買一次的存貨單位 (SKU),例如動作或 Android 應用程式中的付費內容的存取權。這類產品與可購買、使用及重新購買的消耗品數位商品不同。

如要進一步瞭解非消耗性一次性產品,請參閱 Android 說明文件的一次性產品功能

交易流程

本指南將概述進行數位商品交易流程時的各開發步驟。動作處理數位商品的交易時,系統會使用以下流程:

  1. 設定數位購物 API 用戶端:您的動作會使用數位 API 與 Google Play 廣告空間和交易通訊。 在進行任何其他操作之前,系統會建立含有服務金鑰的 JWT 用戶端,以便與數位 Purchases API 進行通訊。
  2. 收集資訊:您的動作會收集關於使用者和 Google Play 庫存的基本資訊,以便為交易做好準備。
    1. 驗證交易規定:您的動作會在購買流程的開頭使用數位交易規定輔助工具,以確保使用者能夠進行交易。
    2. 收集可用廣告空間:動作會檢查您的 Google Play 廣告空間,並找出目前開放購買的商品。
  3. 建立訂單:您的動作會向使用者顯示可用的數位商品,以便使用者選擇一個。
  4. 完成購買:您的動作會使用 Digital Purchase API 啟動使用者所選 Google Play 商店的購買交易。
  5. 處理結果:您的動作會收到交易的狀態碼,並通知使用者購買交易成功 (或需要完成額外步驟)。

限制和審查規範

其他適用於交易的相關政策。這項作業可能需要數週的時間,才能完成含有交易的操作,因此在規劃發布時程時,請將時間納入考量。為簡化審查流程,請務必先遵循交易的政策與規範,再將動作提交審查。

銷售數位商品的動作只能在下列國家/地區部署:

  • 澳洲
  • 巴西
  • 加拿大
  • 印尼
  • 日本
  • 墨西哥
  • 俄羅斯
  • 新加坡
  • 泰國
  • 土耳其
  • 英國
  • United States

必要條件

將數位交易納入動作之前,您必須符合以下條件:

  • Google Play 開發人員帳戶商家帳戶 可在 Google Play 管理中心管理管理數位商品。

  • 在 Google Search Console 中驗證的網域。此網域不需要與公開推出的網站建立關聯,只需要參考您的網站網域即可。

  • Google Play 管理中心有 com.android.vending.BILLING 權限的 Android 應用程式。在 Google Play 管理中心,您的數位商品將與這個應用程式 「應用程式內購」

    您也必須在 Play 管理中心使用這個應用程式建立版本,但如果您不想公開發布版本,可以建立「封閉的 Alpha 測試版」。

    如果您還沒有 Android 應用程式,請參閱「為 Android 應用程式建立關聯」。

  • Google Play 管理中心中的一或多個受管理產品,也就是您使用動作銷售的數位商品。請注意,您必須先設定 Android 應用程式,才能在 Play 管理中心建立納入管理的產品。

    如果您尚未取得納入管理的產品,請按照建立數位商品操作說明進行。

與 Android 應用程式建立關聯

如果您目前沒有透過 Google Play 管理中心取得帳單權限的 Android 應用程式,請按照下列步驟操作:

  1. Android Studio 或您選擇的 Android IDE 中,建立新專案。請在專案設定提示中選擇選項,建立非常基本的應用程式。
  2. 為專案命名,例如 com.mycompany.myapp。請勿將此名稱做為預設值,因為無法將含有 com.example 的套件上傳至 Play 管理中心。
  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. 按一下「Next」
    3. 按一下「Key store path」下方的「Create new」。
    4. 請填寫每個欄位,然後按一下「OK」。請記下「金鑰儲存庫密碼」和「金鑰密碼」,並將這些密碼儲存在安全的地方,因為之後會用到。
    5. 按一下「Next」
    6. 選取「發布」
    7. 選取「V1 (JAR Signature)」
    8. 按一下「Finish」
    9. 幾秒後,Android Studio 會產生 app-release.apk 檔案。找出這個檔案,以便日後使用。
  6. Google Play 管理中心中建立新的應用程式。

  7. 前往「應用程式版本」

  8. 在「封閉測試群組」下方,依序前往「管理」和「Alpha 版」

  9. 按一下「Create Release」(建立版本) 按鈕。

  10. 在「讓 Google 管理及保護您的簽署金鑰」底下,輸入簽署金鑰資訊。

  11. 上傳 APK 檔案。

  12. 按一下「儲存」

建立數位商品

如果 Play 管理中心中目前沒有任何數位商品,請按照下列步驟操作:

  1. Google Play 管理中心,依序前往「應用程式內產品」和「納入管理的產品」。如果看到警告訊息,請按照上述的操作說明建立 Android 應用程式,或是按一下連結來建立商家檔案。
  2. 按一下「建立納入管理的產品」
  3. 填寫數位產品欄位。然後記下產品 ID,這是您希望從動作中參照這項產品的方法。
  4. 按一下「儲存」
  5. 針對您要販售的每項產品重複執行步驟 2 到 4。

Google Play 管理中心的非消耗性商品示例。

準備 Actions 專案

在 Google Play 管理中心設定數位商品後,您必須啟用數位交易,並將 Actions 專案與 Play 應用程式建立關聯。

設定

如要在 Actions 專案中啟用數位商品交易,請按照下列步驟操作:

  1. Actions 主控台中開啟專案或建立新專案。
  2. 依序前往「部署」和「目錄資訊」
  3. 在「其他資訊」和「交易」下方,勾選「如果您的動作使用 Digital Purchase API」即可執行數位商品交易。
  4. 按一下「儲存」

建立數位商品 API 金鑰

如要傳送要求至數位商品 API,您必須下載與 Actions 控制台專案相關聯的 JSON 服務帳戶金鑰。

如要擷取服務帳戶金鑰,請按照下列步驟操作:

  1. 在「Actions 主控台」中,按一下右上角的三點圖示,然後點選「專案設定」
  2. 找出動作的專案 ID
  3. 請點選這個連結,將「<project_id>」替換成您的專案 ID: https://console.developers.google.com/apis/credentials?project=project_id
  4. 在主要導覽列中,前往「憑證」
  5. 在顯示的頁面中,依序按一下「建立憑證」和「服務帳戶金鑰」
  6. 前往「Service Account」(服務帳戶),然後按一下「New Service Account」(新增服務帳戶)
  7. 為服務帳戶命名,例如數位交易。
  8. 按一下「建立」
  9. 將「角色」設為「專案」>「擁有者」
  10. 按一下「繼續」
  11. 按一下 [Create Key] (建立金鑰)
  12. 選取「JSON」金鑰類型。
  13. 按一下「Create key」(建立金鑰),然後下載 JSON 服務帳戶金鑰。

將這個服務帳戶金鑰保存在安全的地方。您將在執行要求中使用此金鑰,為 Digital Purchase API 建立用戶端。

連結至 Play 廣告空間

如要從動作專案存取數位商品,請將您的網頁和應用程式與已連結的資源建立關聯。

如要將 Play 管理中心網域和應用程式連結至動作專案,請按照下列步驟操作:

  1. 動作控制台中,依序前往「部署」和「品牌驗證」
  2. 如果尚未連結任何資源,請先連結網站:

    1. 按一下網站資源 (</>)。
    2. 輸入網站網域的網址,然後按一下「連線」

    Google 會將操作說明透過電子郵件傳送給您的使用者必須在 Google Search Console 中驗證該網域網域的個人。這封電子郵件的收件者完成上述步驟後,網站應會顯示在「Brand authentication」下方。

  3. 至少要連結一個網站後,請按照下列步驟連結 Android 應用程式:

    1. 動作控制台中,依序前往「部署」和「品牌驗證」
    2. 按一下 [連結應用程式]
    3. 在隨即顯示的頁面中,按照操作說明在 Play 管理中心驗證您的網域。選取包含數位商品的 Play 應用程式,並輸入與「品牌驗證」頁面上顯示的網域網址。

      Google 再次傳送驗證電子郵件給網域已驗證的擁有者。對方核准驗證後,您的 Play 應用程式應會顯示在「Brand authentication」下方。

    4. 啟用 [存取 Play 購買項目]

圖片:顯示已連結到 Actions 專案的網站和應用程式。

建立購買流程

備妥 Actions 專案和數位商品清單後,請在對話執行 Webhook 中建構數位商品購買流程。

1. 設定 DigitalPurchases API 用戶端

在對話執行 Webhook 中,使用服務帳戶 JSON 金鑰和 https://www.googleapis.com/auth/actions.purchases.digital 範圍建立 JWT 用戶端。

下列 Node.js 程式碼會為數位商品交易 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. 驗證數位購買規定

建議您先確認使用者帳戶已設定完成交易,再提供購買選項。您應該轉換到 DigitalPurchaseCheck 情境,這會檢查使用者是否已通過驗證,並對允許途徑 (智慧螢幕、智慧音箱或 Android) 執行交易,並確認該交易位於支援數位交易的地區。

如要建立數位購物交易情境,請按照下列步驟操作:

  1. 在「場景」分頁中,新增名為 DigitalPurchaseCheck 的場景。
  2. 在「運算單元填充」下方,按一下「+」新增版位。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.DigitalPurchaseCheckResult 做為運算單元類型。
  4. 在運算單元名稱欄位中,將運算單元命名為 DigitalPurchaseCheck
  5. 啟用「Customize slot value writeback」(自訂運算單元值寫入功能) 核取方塊 (預設為啟用)。
  6. 按一下「儲存」

數位購物交易將導致發生的結果如下:

  • 如果符合上述要求,工作階段參數會以成功條件進行設定,接著您就可以允許使用者購買數位商品。
  • 如果不符合一或多項條件,工作階段參數就會設定失敗。在這種情況下,建議你從交易體驗中移出對話,或是結束對話。

如要處理數位購物交易的檢查結果,請按照下列步驟操作:

  1. 在「Scenes」分頁中,選取新建立的 DigitalPurchaseCheck 情境。
  2. 在「條件」下方,按一下「+」來新增條件。
  3. 在文字欄位中,輸入下列條件語法來檢查成功條件:

    scene.slots.status == "FINAL" && session.params.DigitalPurchaseCheck.resultType == "CAN_PURCHASE"
    
  4. 將滑鼠遊標懸停在剛剛新增的條件上,然後按一下向上箭頭,即可放置 if scene.slots.status == "FINAL" 之前。

  5. 啟用「Send 指明」,並提供簡單的提示,讓使用者知道我們已準備好進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                You are ready to purchase digital goods.
    
  6. 在「Transition」底下選取其他情境,讓使用者可以繼續對話,並繼續進行交易。

  7. 選取條件 else if scene.slots.status == "FINAL"

  8. 啟用「Send 指明」,並提供簡單的提示,告知使用者無法進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: Sorry you cannot perform a digital purchase.
    
  9. 在「轉換」下方,選取「結束對話」以結束對話。

2. b. 收集可用廣告空間

請使用 Digital Purchase API 要求取得目前可用的 Play 商店庫存,再為各項產品建立 JSON 物件陣列。您稍後會參照這個陣列,向使用者顯示可購買的選項。

您的每個數位商品都會以 JSON 格式表示。以下 Node.js 程式碼概述每個 SKU 的預期格式:

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

將 POST 要求傳送至 https://actions.googleapis.com/v3/packages/{packageName}/skus:batchGet 端點,其中 {packageName} 是 Google Play 管理中心的應用程式套件名稱 (例如 com.myapp.digitalgoods),並將結果轉換為 SKU 物件的陣列。

如果只想在結果陣列中擷取特定數位商品,請列出您希望可透過 body.ids 購買的數位商品產品 ID (如 Google Play 管理中心中的每個應用程式內產品底下)。

以下 Node.js 程式碼會要求數位商品 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': conv.session.id,
        'skuType': 'SKU_TYPE_IN_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 物件清單陣列,並建立清單回應,其中包含一個清單項目:

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

conv.session.typeOverrides = [{
   name: 'type_name',
   mode: 'TYPE_REPLACE',
   synonym: {
       entries: entries
   }
}];

conv.add(new List({
   title: 'List title',
   subtitle: 'List subtitle',
   items: items,
}));

依據使用者的選擇建立購買內容

使用者選取一項商品後,您就可以建立訂單。如要這麼做,請在與所選項目相關聯的運算單元中呼叫 Webhook 建立訂單。在執行要求中,將訂單資料儲存至工作階段參數。在相同工作階段的情境中,系統會使用物件物件。

conv.session.params.purchase = {
  "@type": "type.googleapis.com/google.actions.transactions.v3.CompletePurchaseValueSpec",
  "skuId": {
    "skuType": "<SKU_TYPE_IN_APP>",
    "id": "<SKU_ID>",
    "packageName": "<PACKAGE_NAME>"
  },
  "developerPayload": ""
};

在 Actions Builder 中,您可以改用 JSON 編輯器設定上述訂單物件。這兩種實作都會使用 CompletePurchaseValueSpec 的相同格式,詳情請參閱 JSON Webhook 酬載參考資料

4. 完成購買程序

使用者選取一項商品後,你就可以完成購買程序。填充與所選項目相關聯的運算單元後,應轉換為執行完整購買交易的情境。

建立完整的購買場景

  1. 在「場景」分頁中,新增名為 CompletePurchase 的新場景。
  2. 在「運算單元填充」下方,按一下「+」新增版位。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.CompletePurchaseValue 做為運算單元類型。
  4. 在運算單元名稱欄位中,將運算單元命名為 CompletePurchase
  5. 勾選「Customize slot value Copyback」核取方塊 (預設為啟用)。
  6. 在「Configure slot」(設定運算單元) 下方的下拉式選單中,選取 Use session parameter
  7. 在「Configure slot」(設定運算單元) 下方,輸入用於儲存訂單的工作階段參數名稱 (即 $session.params.purchase)。
  8. 按一下「儲存」

5. 處理結果

具有 actions.type.CompletePurchaseValue 類型的運算單元可能包含下列結果:

  • 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:交易因不明原因而失敗,導致不明狀態。請通知使用者交易失敗,並詢問是否要再試一次。

您應透過 CompletePurchase 情境處理這些結果。

  1. 在「Scenes」分頁中,選取新建立的 CompletePurchase 情境。
  2. 在「條件」下方,按一下「+」來新增條件。
  3. 在文字欄位中,輸入下列條件語法來檢查成功條件:

    scene.slots.status == "FINAL" && session.params.CompletePurchase.purchaseStatus == "PURCHASE_STATUS_OK"
    
  4. 將滑鼠遊標懸停在剛剛新增的條件上,然後按一下向上箭頭,即可放置 if scene.slots.status == "FINAL" 之前。

  5. 啟用「Send 指明」,並提供簡單的提示,讓使用者知道我們已準備好進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Your purchase was successful.
    
  6. 在「轉換」下方選取「結束對話」,即可結束對話。

針對您要支援的每種購買結果重複上述步驟。

反映使用者的購買交易

當使用者查詢您的動作時,要求 JSON 的 user 物件會包含一份購買交易清單。請查看這項資訊,並根據使用者付費的內容變更動作的回應。

下列程式碼範例顯示要求的 user 物件,其中含有先前在 com.digitalgoods.application 套件中購買的應用程式內產品 packageEntitlements

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "example_session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
      "packageEntitlements": [
        {
          "packageName": "com.digitalgoods.application",
          "entitlements": [
            {
              "sku": "non-consumable.1",
              "skuType": "SKU_TYPE_IN_APP"
            }
            {
              "sku": "consumable.2",
              "skuType": "SKU_TYPE_IN_APP"
            }
          ]
        },
        {
          "packageName": "com.digitalgoods.application",
          "entitlements": [
            {
              "sku": "annual.subscription",
              "skuType": "SKU_TYPE_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=="
              }
            }
          ]
        }
      ]
     }
   },
  "homeStructure": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

測試專案

測試專案時,您可以在 Actions 主控台啟用沙箱模式來測試動作,無須透過付款方式付費。如要啟用沙箱模式,請按照下列步驟操作:

  1. 在 Actions 主控台按一下導覽中的「測試」
  2. 按一下「設定」。
  3. 啟用「Development Sandbox」選項。