دمج "مكتبة الفوترة في Google Play" في تطبيقك

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

إذا سبق لك الدمج مع مكتبة الفوترة في 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: عرض المنتجات المتوفّرة للشراء

أصبحت الآن جاهزًا لطلب منتجاتك المتاحة وعرضها على المستخدِمين. إنّ طلب تفاصيل المنتجات هو خطوة مهمة قبل عرض منتجاتك على المستخدمين، لأنّه يعرض معلومات المنتجات المترجَمة.

قبل عرض منتج للبيع، تأكَّد من أنّ المستخدم لا يملك المنتج. إذا كان لدى المستخدم منتج مستهلك لا يزال في سجلّ purchases (عمليات الشراء)، يجب استهلاك المنتج قبل أن يتمكّن من شرائه مرة أخرى.

  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.