將 Google Play 帳款服務程式庫整合至應用程式

使用 Play 帳款服務銷售數位產品,為遊戲創造收益。SDK 提供 API,可顯示可購買的產品、啟動購買流程,以及處理購買交易。系統會使用在 Google Play Games 用戶端啟動遊戲的 Google 帳戶,呼叫這些結帳系統 API,且不需要任何額外的登入步驟。

如果您已整合 Android Play 帳款服務程式庫,這些 Play 帳款服務 API 應該會讓您感到熟悉。任何與 Play 帳款服務的伺服器端整合作業,都可以由電腦遊戲重複使用,因為 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 管理中心註冊的產品 ID。
  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 傳送至後端伺服器,以完成處理程序。使用伺服器端 Play Billing API 完成剩餘的處理作業。這項伺服器端整合作業與已整合 Play 帳款服務的 Android 遊戲相同。

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. 如果尚未收到購買交易的確認,請呼叫 BillingClient::AcknowledgePurchase,通知 Google 使用者已取得產品授權。
  4. 如果是消費性產品 (可重複購買的產品),請呼叫 BillingClient::ConsumePurchase,通知 Google 使用者已取得產品授權。

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 帳款服務的整合功能。如要在開發階段進行測試,建議您使用授權測試人員。授權測試人員可以測試付款方式,而不會向測試人員真正收取購買交易的費用。

如需設定授權測試人員和一組手動測試的操作說明,建議您參閱如何測試 Google Play 帳款服務程式庫整合的說明文件。