Создавайте потребляемые цифровые транзакции (Dialogflow)

В этом руководстве объясняется, как добавить цифровые транзакции в ваше диалоговое действие, чтобы пользователи могли покупать ваши потребляемые цифровые товары.

Ключевые термины. Потребляемый цифровой товар — это товарная единица (SKU), которую пользователь может использовать и приобретать более одного раза, например, количество внутриигровой валюты в игре для Android. Этот цифровой товар отличается от непотребляемого цифрового товара, который пользователь может приобрести только один раз.

Дополнительную информацию о расходных одноразовых продуктах см. в документации Android по функциям одноразовых продуктов .

Ограничения и рекомендации по проверке

К Действиям с транзакциями применяются дополнительные политики. Проверка действий, включающих транзакции, может занять несколько недель, поэтому учтите это время при планировании графика выпуска. Чтобы облегчить процесс проверки, убедитесь, что вы соблюдаете правила и рекомендации для транзакций, прежде чем отправлять свое действие на проверку.

Действия по продаже цифровых товаров могут быть развернуты только в следующих странах:

  • Австралия
  • Бразилия
  • Канада
  • Индонезия
  • Япония
  • Мексика
  • Россия
  • Сингапур
  • Таиланд
  • Турция
  • Великобритания
  • Соединенные Штаты

Поток транзакций

В этом руководстве описываются все этапы разработки в том виде, в каком они происходят в потоке транзакций цифровых товаров. Когда ваше действие обрабатывает транзакции с цифровыми товарами, оно использует следующий поток:

  1. Настройте клиент API цифровых покупок . Ваше действие использует API цифровых покупок для связи с вашим инвентарем Google Play и совершения транзакций. Прежде чем ваше действие сделает что-либо еще, оно создает клиент JWT со служебным ключом для связи с API цифровых покупок.
  2. Сбор информации . Ваше действие собирает основную информацию о пользователе и вашем инвентаре в Google Play для подготовки к транзакции.
    1. Проверка требований к транзакции . Ваше действие использует помощник по требованиям к цифровым транзакциям в начале процесса покупки, чтобы убедиться, что пользователь может совершить транзакцию.
    2. Соберите доступный инвентарь . Ваше действие проверяет ваш инвентарь в Google Play и определяет, какие предметы в настоящее время доступны для покупки.
  3. Создайте заказ : ваше действие представляет пользователю доступные цифровые товары, чтобы он мог выбрать один для покупки.
  4. Завершите покупку . Ваше действие использует API цифровых покупок, чтобы инициировать покупку по выбору пользователя в магазине Google Play.
  5. Обработка результата : ваше действие получает код состояния транзакции и уведомляет пользователя об успешной покупке (или предпринимает дополнительные действия).
  6. Сделайте покупку повторяемой : ваше действие использует API цифровых покупок для «потребления» приобретенного товара, делая этот товар снова доступным для покупки этим пользователем.

Предварительные условия

Прежде чем включить цифровые транзакции в свое действие, вам необходимы следующие предварительные условия:

Свяжите приложение для 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. Перейдите в раздел «Сборка» , «Создать подписанный пакет / APK» .
    2. Нажмите Далее .
    3. В разделе «Путь к хранилищу ключей» нажмите « Создать новый» .
    4. Заполните каждое поле и нажмите «ОК» . Запишите свой пароль хранилища ключей и пароль ключа и сохраните их в надежном месте, так как они вам понадобятся позже.
    5. Нажмите Далее .
    6. Выберите выпуск .
    7. Выберите V1 (подпись JAR) .
    8. Нажмите «Готово» .
    9. Через несколько секунд Android Studio создаст файл app-release.apk . Найдите этот файл для дальнейшего использования.
  6. В консоли Google Play создайте новое приложение.

  7. Перейдите в раздел «Выпуски приложений» .

  8. В разделе «Закрытые треки» выберите «Управление» , затем «Альфа» .

  9. Нажмите кнопку «Создать выпуск» .

  10. В разделе «Разрешить Google управлять вашим ключом подписи и защищать его» введите информацию о своем ключе подписи.

  11. Загрузите свой APK-файл.

  12. Нажмите Сохранить .

Создайте свои цифровые товары

Если у вас в настоящее время нет цифровых товаров в консоли Play, выполните следующие действия:

  1. В консоли Google Play выберите «Продукты для продажи в приложении», а затем «Управляемые продукты» . Если вы видите предупреждение, следуйте предыдущим инструкциям, чтобы создать приложение для Android, или нажмите ссылку, чтобы создать профиль продавца.
  2. Нажмите Создать управляемый продукт .
  3. Заполните поля для вашего цифрового продукта. Запишите идентификатор продукта, по которому вы будете ссылаться на этот продукт в своем действии.
  4. Нажмите Сохранить .
  5. Повторите шаги 2–4 для каждого продукта, который вы хотите продать.

Пример расходных товаров в консоли Google Play.

Подготовьте проект действий

Настроив цифровые товары в консоли Google Play, вы должны включить цифровые транзакции и связать свой проект Actions с приложением Play.

Чтобы включить транзакции с цифровыми товарами в проекте Actions, выполните следующие действия:

  1. В консоли «Действия» откройте свой проект или создайте новый.
  2. Перейдите в раздел «Развертывание» , затем «Информация о каталоге» .
  3. В разделе «Дополнительная информация и транзакции» установите флажок «Да» в разделе «Используют ли ваши действия API цифровых покупок для выполнения транзакций с цифровыми товарами» .
  4. Нажмите Сохранить .

Создайте ключ API цифровых товаров

Чтобы отправлять запросы к API цифровых товаров, вам необходимо загрузить ключ учетной записи службы JSON, связанный с вашим проектом консоли Actions.

Чтобы получить ключ сервисной учетной записи, выполните следующие действия:

  1. В консоли «Действия» щелкните значок с тремя точками в правом верхнем углу, затем выберите «Настройки проекта».
  2. Найдите идентификатор проекта вашего действия.
  3. Перейдите по этой ссылке, заменив « <project_id> » идентификатором вашего проекта: https://console.developers.google.com/apis/credentials?project=project_id
  4. В главной навигации перейдите в раздел «Учетные данные» .
  5. На появившейся странице нажмите «Создать учетные данные» , затем «Ключ сервисной учетной записи» .
  6. Перейдите в раздел «Учетная запись службы» и нажмите «Новая учетная запись службы» .
  7. Присвойте учетной записи службы имя, например digitaltransactions.
  8. Нажмите Создать .
  9. Установите роль Project > Owner .
  10. Нажмите Продолжить .
  11. Нажмите Создать ключ .
  12. Выберите тип ключа JSON .
  13. Нажмите «Создать ключ» и загрузите ключ учетной записи службы JSON.

Сохраните этот ключ сервисной учетной записи в надежном месте. Вы будете использовать этот ключ для создания клиента для API цифровых покупок.

Подключитесь к своему инвентарю Play

Чтобы получить доступ к своим цифровым товарам из проекта Actions, свяжите свой веб-домен и приложение с проектом как подключенные свойства .

Примечание. Процесс подключения может занять до недели, пока мы проверим ваши объекты. Если по истечении этого времени ссылка на ваш веб-сайт или приложение не будет установлена, обратитесь в службу поддержки .

Чтобы подключить веб-домен и приложение консоли Play к проекту Actions, выполните следующие действия:

  1. В консоли «Действия» выберите «Развертывание», затем «Проверка бренда» .
  2. Если вы не подключили ни одного объекта, сначала подключите веб-сайт:

    1. Нажмите кнопку веб-ресурса ( </> ).
    2. Введите URL-адрес своего веб-домена и нажмите « Подключиться» .

    Google отправляет электронное письмо с дальнейшими инструкциями лицу, подтвердившему этот веб-домен в консоли поиска Google . Как только получатель этого письма выполнит эти действия, веб-сайт должен появиться в разделе «Проверка бренда» .

  3. Если у вас есть хотя бы один подключенный веб-сайт, выполните следующие действия, чтобы подключить приложение Android:

    1. В консоли «Действия» выберите «Развертывание», затем «Проверка бренда» .
    2. Нажмите «Подключить приложение» .
    3. На появившейся странице следуйте инструкциям, чтобы подтвердить свой веб-домен на консоли Play. Выберите приложение Play, содержащее ваши цифровые товары, и введите URL-адрес веб-домена точно так, как он показан на странице проверки бренда .

      Google еще раз отправляет подтверждающее электронное письмо подтвержденному владельцу домена. Как только они одобряют проверку, ваше приложение Play должно появиться в разделе «Проверка бренда» .

    4. Включите покупки в Access Play .

Изображение, показывающее веб-сайт и приложения, связанные с проектом Actions.

Создайте свой поток покупок

Подготовив проект Actions и инвентарь цифровых товаров, создайте поток покупки цифровых товаров в веб-перехватчике для выполнения разговоров.

1. Настройте API-клиент цифровых покупок.

В веб-перехватчике выполнения разговора создайте клиент JWT с ключом JSON вашего сервисного аккаунта и областью действия https://www.googleapis.com/auth/actions.purchases.digital .

Следующий код Node.js создает клиент JWT для API цифровых покупок:

  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. а. Проверка требований к транзакции

Рекомендуется убедиться, что учетная запись пользователя настроена для выполнения транзакций, прежде чем предоставлять ему возможность совершить покупку. Этот шаг включает проверку того, что у пользователя настроен способ оплаты и что он находится в языковом стандарте, где поддерживаются цифровые транзакции. В начале потока транзакции используйте помощник 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 для каждого продукта. Вы ссылаетесь на этот массив позже, чтобы показать пользователю, какие опции доступны для покупки.

Каждый ваш цифровой товар представлен в виде SKU в формате JSON. Следующий код 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.

Чтобы получить в результирующем массиве только определенные цифровые товары, укажите идентификаторы цифровых товаров (как показано под каждым продуктом в приложении в консоли 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 с элементом, выбранным пользователем.

Следующий код 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. Работайте с результатом

Когда покупка завершается, она запускает событие Dialogflow actions_intent_COMPLETE_PURCHASE (или 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);
  }
});

6. Сделайте покупку повторяемой

Используйте API цифровых покупок, чтобы запросить доступный на данный момент инвентарь в магазине Play, а затем встроить его в массив объектов JSON для каждого продукта. Вы ссылаетесь на этот массив позже, чтобы показать пользователю, какие опции доступны для покупки.

Каждый ваш цифровой товар представлен в виде SKU в формате JSON. Следующий код 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.

Чтобы получить в результирующем массиве только определенные цифровые товары, укажите идентификаторы цифровых товаров (как показано под каждым продуктом в приложении в консоли 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));
    });
  });
});

Отражать покупки пользователя

Когда пользователь запрашивает ваше действие, объект user JSON запроса включает список его покупок. Проверьте эту информацию и измените ответ вашего действия в зависимости от того, за какой контент заплатил пользователь.

В следующем примере кода показан 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"
        }
      ]
    }
  ],
  ...
}