שילוב של ספריית החיוב ב-Google Play למחשבים מקומיים באפליקציה

אפשר להפעיל מונטיזציה במשחק על ידי מכירת מוצרים דיגיטליים באמצעות מערכת החיוב ב-Play. חבילת ה-SDK כוללת ממשקי API להצגת מוצרים שזמינים לרכישה, להפעלת תהליך הרכישה ולעיבוד הרכישות. הקריאות לממשקי ה-API האלה לחיוב מתבצעות באמצעות חשבון Google שהפעיל את המשחק בתוך לקוח Google Play Games, ולא נדרשים שלבי כניסה נוספים.

אם שילבתם את ספריית החיובים ב-Play ל-Android, ממשקי ה-API האלה של החיובים ב-Play אמורים להיראות לכם מוכרים. אפשר לעשות שימוש חוזר בכל שילוב בצד השרת עם מערכת החיוב של 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 Console.
  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 בצד השרת. השילוב הזה מצד השרת זהה לשילוב שנעשה במשחק ל-Android שמשולבת בו מערכת החיוב ב-Play.

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. כדי לבצע בדיקות במהלך שלב הפיתוח, מומלץ להשתמש בבודקי רישיונות. בודקי הרישיון יכולים לגשת לתשלומים לצורך בדיקה, שלא מחייבים כסף אמיתי על רכישות.

הוראות להגדרת בודקי רישיונות וסדרה של בדיקות ידניות מומלצות מופיעות במסמכי התיעוד בנושא בדיקת השילוב של Google Play Billing Library.