دمج مكتبة الفوترة في Google Play للألعاب المخصَّصة للكمبيوتر في تطبيقك

يمكنك تحقيق الربح من لعبتك من خلال بيع منتجات رقمية باستخدام خدمة "الفوترة في Play". توفر حزمة تطوير البرامج (SDK) واجهات برمجة تطبيقات لعرض المنتجات المتاحة للشراء، وبدء عملية الشراء، ومعالجة عمليات الشراء. يتم تنفيذ طلبات البيانات من واجهات برمجة التطبيقات لنظام الفوترة هذه باستخدام حساب Google الذي تم من خلاله تشغيل اللعبة داخل برنامج "ألعاب Google Play"، ولا تتطلّب أي خطوات إضافية لتسجيل الدخول.

إذا كنت قد أجريت عملية الدمج مع مكتبة الفوترة في Android Play، من المفترض أن تكون على دراية بواجهات برمجة التطبيقات الخاصة بخدمة "الفوترة في 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" من جهة الخادم. ويكون هذا الدمج من جهة الخادم مماثلاً لما يتم إجراؤه في لعبة 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.