构建消耗型数字交易 (Dialogflow)

本指南介绍了如何将数字交易添加到对话 使用户可以购买您的消耗型数字商品。

关键术语:消耗型数字商品是指库存量单位 (SKU), 用户可以多次使用和购买,例如一定数量的游戏代币 是 Android 游戏的理想平台此数字商品与非消耗品不同 用户只能购买一次的数字商品

有关消耗型一次性商品的详情,请参阅 Android 关于 一次性商品专用功能。

限制和查看指南

其他政策适用于涉及交易的操作。这可能需要 查看包含交易的操作数,因此请将这一时间因素考虑在内 规划发布时间表。为了简化审核流程,请确保您符合 替换为 交易政策和准则 然后再提交 Action 以供审核。

销售数字商品的操作只能在以下国家/地区部署:

  • 澳大利亚
  • 巴西
  • 加拿大
  • 印度尼西亚
  • 日本
  • 墨西哥
  • 俄罗斯
  • 新加坡
  • 泰国
  • 土耳其
  • 英国
  • 美国
。

交易流程

本指南概述了数字商品中涉及的每个开发步骤 交易流程当您的 Action 处理数字商品交易时,它 采用以下流程:

  1. 设置数字购买 API 客户端:您的 Action 会使用数字 购买 API 与您的 Google Play 广告资源进行通信并进行交易。 在您的 Action 执行任何其他操作之前,它会创建一个具有 与数字购买 API 通信的服务密钥。
  2. 收集信息:您的 Action 会收集有关 用户和 Google Play 广告资源来为交易做准备
    1. 验证交易要求:您的 Action 使用数字 交易要求帮助程序(在购买流程开始时提供) 确保用户能够进行交易
    2. 收集可用的广告资源:您的 Action 检查您的 Google Play 广告资源,并确定当前可供购买的商品。
  3. 构建订单:您的 Action 会向用户展示可用的数字商品 以便用户选择一个商品进行购买。
  4. 完成购买:您的 Action 会使用 digitalPurchases API 来 通过用户从 Google Play 商店中选择的内容发起购买。
  5. 处理结果:您的 Action 会收到 并通知用户购买成功 其他步骤)。
  6. 确保购买交易可重复:您的 Action 会使用数字购买交易 通过 API 来“使用”使该商品可供购买 再次执行相应操作

前提条件

在将数字交易纳入你的 Action 之前,你需要 以下前提条件:

关联 Android 应用

如果您目前没有拥有结算权限的 Android 应用 Google Play 管理中心,请按以下步骤操作:

  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. 点击下一步。
    3. 在 Key store path 下,点击 Create new。
    4. 填写每个字段,然后点击 OK。记下您的密钥库 密码和密钥密码,并妥善保存,因为 稍后会用到它们
    5. 点击下一步。
    6. 选择发布。
    7. 选择 V1 (JAR Signature)。
    8. 点击完成。
    9. 几秒钟后,Android Studio 会生成一个 app-release.apk 文件。 找到此文件以供稍后使用。
  6. 在 Google Play 管理中心、 创建新应用。

  7. 前往应用版本页面。

  8. 在封闭式轨道下,依次前往管理和 Alpha 版。

  9. 点击创建版本按钮。

  10. 在让 Google 管理和保护您的签名密钥下方,输入您的签名 关键信息

  11. 上传 APK 文件。

  12. 点击保存。

创建你的数字商品

如果您当前在 Play 管理中心内没有任何数字商品,请按以下方法操作 步骤:

  1. 在 Google Play 管理中心、 依次点击应用内商品和受管理的商品。如果您看到警告 按照上述说明创建 Android 应用,或点击链接 创建商家资料。
  2. 点击创建受管理的商品。
  3. 填写数字商品对应的字段。记下产品 ID 这就是您在 Action 中引用此商品的方式。
  4. 点击保存。
  5. 针对您要销售的每件商品重复第 2-4 步。

Google Play 管理中心内的消耗品示例。

准备 Actions 项目

在 Google Play 管理中心内设置数字商品后,您必须启用 进行数字交易,并将您的 Actions 项目与您的 Play 应用相关联。

如需在 Actions 项目中启用数字商品交易,请按以下步骤操作: 步骤:

  1. 在 Actions 控制台中,打开你的项目或创建一个新项目。
  2. 转到部署,然后选择目录信息。
  3. 在其他信息和交易下,选中是复选框 在您的 Action 会使用 Digital Purchase API 执行交易吗? 数字商品”。
  4. 点击保存。

创建数字商品 API 密钥

如需向数字商品 API 发送请求,您需要下载 JSON 服务 与 Actions 控制台项目关联的账号密钥。

如需检索您的服务账号密钥,请按以下步骤操作:

  1. 在 Actions 控制台中,点击右上角的三点状图标。 然后选择项目设置。
  2. 找到 Action 的 Project ID。
  3. 访问此链接,替换“<project_id>”替换为您的项目 ID: https://console.developers.google.com/apis/credentials?project=project_id
  4. 在主导航栏中,前往凭据。
  5. 在显示的页面上,点击创建凭据,然后点击服务 账号密钥。
  6. 转到服务账号,然后点击新的服务账号。
  7. 为服务账号命名,例如 digitaltransactions。
  8. 点击创建。
  9. 将角色设置为项目 >所有者。
  10. 点击继续。
  11. 点击创建密钥。
  12. 选择 JSON 密钥类型。
  13. 点击创建密钥并下载 JSON 服务账号密钥。

请妥善保存此服务账号密钥。您将在自己的 执行方式为 DigitalPurchases API 创建客户端。

关联到您的 Play 广告资源

为了从 Actions 项目访问您的数字商品,您需要将您的 域名和应用 关联的媒体资源。

注意:我们会在验证期间完成关联步骤,最多可能需要一周时间才能完成 媒体资源如果这段时间过后您的网站或应用还未建立关联, 与支持团队联系。

如需将 Play 管理中心网站网域和应用关联到 Actions 项目,请按以下步骤操作: 具体步骤:

  1. 在 Actions 控制台中,依次点击部署和品牌验证。
  2. 如果您尚未关联任何媒体资源,请先关联网站:

    1. 点击网络媒体资源 (&lt;/&gt;) 按钮。
    2. 输入您网域的网址,然后点击连接。

    Google 会向 已在 Google Search Console。 这封电子邮件的收件人完成上述步骤后,网站应该就会 品牌验证下会显示相应信息。

  3. 您至少关联了一个网站后,请执行以下步骤 关联您的 Android 应用:

    1. 在 Actions 控制台中,依次点击部署和品牌验证。
    2. 点击关联应用。
    3. 在随即显示的页面上,按照说明验证网站 登录该网域选择包含 数字商品,然后输入与 品牌验证页面。

      Google 会再次向以下经过验证的所有者发送验证电子邮件: 网域。他们批准验证后,您的 Play 应用应该 品牌验证下会显示相应信息。

    4. 启用访问 Play 购买交易。

显示已关联到 Actions 项目的网站和应用的图片。

构建购买流程

准备好 Actions 项目和数字商品清单后,构建数字商品 商品购买流程。

1. 设置数字购买 API 客户端

在对话 fulfillment 网络钩子中,使用您的服务创建一个 JWT 客户端 账号 JSON 密钥和 https://www.googleapis.com/auth/actions.purchases.digital 范围。

以下 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. 收集信息

您的 Action 会收集有关 用户购买行为的能力以及可通过 Google 地图购买哪些商品 广告资源。

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.收集可用的广告资源

使用数字购买 API 请求您当前可用的 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
  ]
}

将 POST 请求发送到 https://actions.googleapis.com/v3/packages/{packageName}/skus:batchGet 端点,其中 {packageName} 是您的应用在 Google Play 中的软件包名称 控制台(例如 com.myapp.digitalgoods),并将结果的格式设置为 一组 SKU 对象。

如需仅检索结果数组中的特定数字商品,请列出相应商品 数字商品 ID(如 Google Play 中每个应用内商品下方所示) 控制台)。body.ids

以下 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': conversationId,
        'skuType': 'APP',
        // This request is filtered to only retrieve SKUs for the following product IDs
        'ids': ['consumable.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 对象的库存数组,并创建 列出响应,其中包含一个用于 :

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 帮助程序 intent 与 与用户选择的内容相关联。

以下 Node.js 代码会处理用户在列表响应中选择的 SKU 并请求包含相应信息的 COMPLETE_PURCHASE intent:

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 intent) 描述结果的 COMPLETE_PURCHASE_VALUE 参数。构建一个 intent 将结果传达给用户。

处理以下可能的购买结果:

  • 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);
  }
});

6. 使购买交易可重复

使用数字购买 API 请求您当前可用的 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
  ]
}

将 POST 请求发送到 https://actions.googleapis.com/v3/packages/{packageName}/skus:batchGet 端点,其中 {packageName} 是您的应用在 Google Play 中的软件包名称 控制台(例如 com.myapp.digitalgoods),并将结果的格式设置为 一组 SKU 对象。

如需仅检索结果数组中的特定数字商品,请列出相应商品 数字商品 ID(如 Google Play 中每个应用内商品下方所示) 控制台)。body.ids

以下 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': conversationId,
        'skuType': 'APP',
        // This request is filtered to only retrieve SKUs for the following product IDs
        'ids': ['consumable.1']
      },
    }, (err, httpResponse, body) => {
      if (err) {
        throw new Error(`API request error: ${err}`);
      }
      console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`);
      console.log(JSON.stringify(body));
    });
  });
});

反映用户的购买情况

当用户查询您的 Action 时,请求 JSON 的 user 对象会包含一个列表 用户购买的产品/服务请查看此信息并更改你的 Action 的回应 根据用户付费的内容付费

以下示例代码展示了请求的 user 对象,该对象包含 占之前应用内购买交易的 packageEntitlements com.digitalgoods.application 软件包:

  "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"
        }
      ]
    }
  ],
  ...
}