Интегрируйте библиотеку Google Play для выставления счетов на ПК в свое приложение

Монетизируйте свою игру, продавая цифровые продукты с помощью Play Billing. SDK предоставляет API для отображения доступных для покупки продуктов, запуска процесса покупки и обработки платежей. Вызовы к этим платежным API выполняются с использованием учетной записи Google, которая запустила игру в клиенте Google Play Games, и не требуют дополнительных шагов входа в систему.

Если вы интегрировались с библиотекой Android Play Billing , эти API Play Billing должны показаться вам знакомыми. Любые серверные интеграции с Play Billing можно повторно использовать в играх для ПК, поскольку они одинаковы как для Android, так и для ПК.

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

Шаг 1 : Запрос информации о предыдущих покупках и покупках, совершенных вне вашего приложения.

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

  1. Запрос покупок с использованием BillingClient::QueryPurchases .

  2. Продолжите обработку покупок .

// Query for purchases when:
// - Application starts up
// - Application window re-enters the foreground
auto promise = std::make_shared<std::promise<QueryPurchasesResult>>();
billing_client.QueryPurchases([promise](QueryPurchasesResult result) {
   promise->set_value(std::move(result));
});

auto query_purchases_result = promise->get_future().get();
if (query_purchases_result.ok()) {
  auto purchases = query_purchases_result.value().product_purchase_details;
  // Process the purchases
} else {
  // Handle the error
}

Шаг 2 : Отобразите товары, доступные для покупки.

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

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

  1. Запросите подробную информацию о продукте, используя BillingClient::QueryProductDetails . Передайте идентификаторы продуктов, зарегистрированных вами в консоли Google Play.
  2. Отобразите элемент ProductDetails , включающий локализованное название товара и цену предложения.
  3. Сохраните ссылку на offer_token продукта. Он используется для запуска процесса покупки по предложению.
QueryProductDetailsParams params;
params.product_ids.push_back({"example_costmetic_1", ProductType::kTypeInApp});
params.product_ids.push_back({"example_costmetic_1", ProductType::kTypeInApp});
params.product_ids.push_back({"example_battle_pass", ProductType::kTypeInApp});

auto promise = std::make_shared<std::promise<QueryProductDetailsResult>>();
billing_client.QueryProductDetails(params, [promise](QueryProductDetailsResult result) {
   promise->set_value(std::move(result));
});

auto query_product_details_result = promise->get_future().get();
if (query_product_details_result.ok()) {
   auto product_details = query_product_details_result.value().product_details;
   // Display the available products and their offers to the user
} else {
   // Handle the error
}

Шаг 3 : Запуск процесса покупки

Когда пользователь выражает намерение приобрести товар, это означает, что вы готовы запустить процесс покупки.

  1. Для начала вызовите BillingClient::LaunchPurchaseFlow() . Передайте в него offer_token полученный при запросе сведений о продукте.
  2. После завершения покупки будет вызвана функция продолжения с результатом.
  3. В случае успеха, продолжение будет содержать ProductPurchaseDetails . Продолжите, обработав покупку .
LaunchPurchaseFlowParams params { product_offer.offer_token };

auto promise = std::make_shared<std::promise<LaunchPurchaseFlowResult>>();
billing_client.LaunchPurchaseFlow(params, [promise](LaunchPurchaseFlowResult result) {
   promise->set_value(std::move(result));
});
// The purchase flow has started and is now in progress.

auto launch_purchase_flow_result = promise->get_future().get();

// The purchase flow has now completed.
if (launch_purchase_flow_result.ok()) {
   auto purchase = launch_purchase_flow_result.value().product_purchase_details;
   // Process the purchase
} else if (launch_purchase_flow_result.code() == BillingError::kUserCanceled) {
   // Handle an error caused by the user canceling the purchase flow
} else {
   // Handle any other error codes
}

Шаг 4 : Обработка покупки

Обработка с использованием бэкэнд-сервера.

Для игр с бэкэнд-сервером завершите обработку, отправив purchase_token на ваш бэкэнд-сервер. Завершите оставшуюся часть обработки, используя API Play Billing на стороне сервера . Эта интеграция на стороне сервера аналогична той, что используется для игр Android, интегрированных с Play Billing.

void ProcessPurchasesWithServer(std::vector<ProductPurchaseDetails> purchases) {
   std::vector<std::string> purchase_tokens;
   for (const auto& purchase : purchases) {
      purchase_tokens.push_back(purchase.purchase_token);
   }

   // Send purchase tokens to backend server for processing
}

Процесс без бэкэнд-сервера

  1. Убедитесь, что платеж пользователя не находится в состоянии ожидания, проверив, что ProductPurchaseDetails::purchase_state имеет значение PurchaseState::kPurchaseStatePurchased . Если состояние покупки находится в состоянии ожидания, сообщите пользователю, что ему необходимо выполнить дополнительные шаги, прежде чем он сможет получить приобретенный товар.

  2. Предоставьте пользователю доступ к приобретенному продукту и обновите хранилище прав доступа вашей игры.

  3. Для товаров, не являющихся расходными материалами (товаров, которые можно приобрести только один раз), проверьте, была ли покупка уже подтверждена, используя ProductPurchaseDetails::is_acknowledged .

    1. Если покупка не подтверждена, сообщите Google о предоставлении пользователю права на продукт, вызвав BillingClient::AcknowledgePurchase .
  4. Для товаров, которые можно приобрести несколько раз (товаров, которые можно купить повторно), сообщите Google о том, что пользователю предоставлено право на приобретение данного товара, вызвав BillingClient::ConsumePurchase .

void ProcessPurchasesWithoutServer(std::vector<ProductPurchaseDetails> purchases) {
   std::vector<std::string> entitled_product_ids;
   for (const auto& purchase : purchases) {
      auto was_successful = ProcessPurchasePurchaseWithoutServer(purchase);
      if (was_successful) {
         entitled_product_ids.push_back(purchase.product_id);
      }
   }

   // Note that non-consumable products that were previously purchased may have
   // been refunded. These purchases will stop being returned by
   // `QueryPurchases()`. If your game has given a user access to one of these
   // products storage they should be revoked.
   //
   // ...
}

bool ProcessPurchasePurchaseWithoutServer(ProductPurchaseDetails purchase) {
   auto is_purchase_completed =
      purchase.purchase_state == PurchaseState::kPurchaseStatePurchased;
   if (!is_purchase_completed) {
      // Notify the user that they need to take additional steps to complete
      // this purchase.
      return false;
   }

   // Determine if the product ID is associated with a consumable product.
   auto is_consumable = IsConsumableProductId(purchase.product_id);
   if (is_consumable) {
      // Grant an entitlement to the product to the user.
      // ...
      // Then, notify Google by consuming the purchase.

      ConsumePurchaseParams params { purchase.purchase_token };
      auto promise = std::make_shared<std::promise<ConsumePurchaseResult>>();
      billing_client.ConsumePurchase(params, [promise](ConsumePurchaseResult result) {
         promise->set_value(std::move(result));
      });

      auto consume_purchase_result = promise->get_future().get();
      if (!consume_purchase_result.ok()) {
         // Examine the failure code & message for more details & notify user
         // of failure.
         // ...
         return false;
      }

      return true;
   }

   // Otherwise the product is assumed to be a non-consumable.

   // Grant an entitlement to the product to the user.
   // ...
   // Then, notify Google by acknowledging the purchase (if not already done).

   if (purchase.is_acknowledged) {
      return true;
   }

   AcknowledgePurchaseParams params { purchase.purchase_token };
   auto promise = std::make_shared<std::promise<AcknowledgePurchaseResult>>();
   billing_client.AcknowledgePurchase(params, [promise](AcknowledgePurchaseResult result) {
      promise->set_value(std::move(result));
   });

   auto acknowledge_purchase_result = promise->get_future().get();
   if (!acknowledge_purchase_result.ok()) {
      // Examine the failure code & message for more details & notify user
      // of failure.
      // ...
      return false;
   }

   return true;
}

Шаг 5 : Проверьте интеграцию

Теперь вы готовы протестировать интеграцию с Play Billing. Для тестирования на этапе разработки мы рекомендуем использовать лицензионных тестировщиков . Лицензионные тестировщики имеют доступ к тестовым платежам, которые позволяют избежать списания реальных денег за покупки.

Инструкции по настройке тестеров лицензий и набор рекомендуемых нами ручных тестов см. в документации по тестированию интеграции библиотеки Google Play Billing .