1. مقدمة
يعلّمك هذا الدرس التطبيقي حول الترميز كيفية استخدام "مكتبة الفوترة في Google Play" (PBL) لإدارة تغييرات خطة الاشتراك. ستتعرّف على كيفية تأثير أوضاع الاستبدال المختلفة في الأسعار وأذونات المستخدمين، بالإضافة إلى كيفية معالجة "إشعارات في الوقت الفعلي خاصة بالمطوّرين" (RTDN) في الخلفية.
الجمهور
تم تصميم هذا الدرس التطبيقي حول الترميز لمطوّري تطبيقات Android، وهو يقدّم إرشادات حول تنفيذ ميزات متطوّرة لإدارة الاشتراكات. تساعدك الإرشادات في توفير تجربة سلسة للمستخدمين للترقية أو الرجوع إلى إصدار أقدم أو الانتقال بين خطط اشتراك مختلفة.
ما ستتعلمه...
- كيفية إنشاء الاشتراكات في Play Console
- كيفية اختيار
ReplacementModeالصحيح (مثلWITH_TIME_PRORATIONمقابلDEFERRED) بما يتوافق مع سياسات الترقية والرجوع إلى إصدار أقدم في تطبيقك - كيفية ضبط
BillingFlowParamsضمنlaunchBillingFlowلتفعيل مسار الشراء على Google Play من أجل استبدال الخطة - كيفية استخدام "الإشعارات في الوقت الفعلي الخاصة بالمطوّرين" (RTDN) وواجهة برمجة التطبيقات
purchases.subscriptionsv2لإبطال إذن الوصول القديم ومنح إذن وصول جديد بأمان على الخلفية
المتطلبات
- الوصول إلى Google Play Console باستخدام حساب مطوِّر إذا لم يكن لديك حساب مطوِّر، عليك إنشاء حساب.
- نموذج التطبيق لهذا الدرس التطبيقي حول الترميز الذي يمكنك تنزيله من GitHub
- استوديو Android
2. إنشاء نموذج التطبيق
يستخدم هذا الدرس التطبيقي حول الترميز نموذجًا لتطبيق Android ليوضّح لك كيفية تنفيذ عمليات استبدال الاشتراكات في "الفوترة في Play". تم تصميم نموذج التطبيق ليكون تطبيق Android يعمل بكامل وظائفه ويتضمّن الرمز المصدر الكامل الذي يعرض الجوانب التالية:
- دمج التطبيق مع PBL
- تنفيذ عمليات استبدال الاشتراكات
إذا كنت على دراية باستبدال الاشتراكات وPBL، يمكنك تنزيل نموذج تطبيق واستخدامه.
يوضّح الفيديو التجريبي التالي كيف سيبدو نموذج التطبيق وكيف سيتصرف بعد نشره وتشغيله.
المتطلبات الأساسية
قبل إنشاء نموذج التطبيق ونشره، عليك تنفيذ ما يلي:
- إنشاء حساب مطوِّر على Google Play Console إذا كان لديك حساب مطوِّر، يمكنك تخطّي هذه الخطوة.
- أنشئ تطبيقًا جديدًا في Play Console مع تفعيل ميزات تحقيق الربح. بدلاً من ذلك، يمكنك استخدام تطبيق حالي في Play Console. إذا لم تكن ميزات تحقيق الربح مفعّلة في تطبيقك، اتّبِع هذه الخطوات لإعدادها.
- ثبِّت استوديو Android.
إنشاء
لإنشاء نموذج التطبيق على النحو المطلوب لمتابعة الدرس التطبيقي حول الترميز، اتّبِع الخطوات التالية:
- نزِّل نموذج التطبيق من GitHub.
- عدِّل
applicationIdفيbuild.gradleلتطبيق العيّنة ليعكس رقم تعريف تطبيقك في Play Console. - إنشاء نموذج التطبيق
ملاحظة: يؤدي ذلك إلى إنشاء التطبيق بنجاح لإجراء الاختبار المحلي. ومع ذلك، لا يؤدي تشغيل التطبيق إلى جلب المنتجات والأسعار لأنّ الاشتراكات المطلوبة لم يتم إنشاؤها بعد في Play Console. سيتناول القسم التالي كيفية إنشاء اشتراكات في Developer Console.
3- إنشاء اشتراكات في Play Console
يتميز نظام الاشتراكات في Google Play بالمرونة التي يوفّرها في طرق إنشاء الاشتراكات وإدارتها وبيعها. في Play Console، يمكنك إعداد الاشتراكات بعدة خطط أساسية، يحتوي كل منها على عروض متعددة. يمكن أن تشمل عروض الاشتراك نماذج أسعار وخيارات أهلية مختلفة. في هذا الدرس التطبيقي حول الترميز، ستنشئ ثلاثة اشتراكات: خطة Premium والخطة الأساسية وخطة Lite، وذلك لمحاكاة عرض اشتراك نموذجي بنقاط أسعار مختلفة. سيتضمّن كلّ منها خطة أساسية شهرية متكرّرة واحدة.
إنشاء اشتراك جديد
لإنشاء اشتراك جديد، اتّبِع الخطوات التالية:
- افتح Play Console وانتقِل إلى صفحة "الاشتراكات" (تحقيق الربح من خلال Play > المنتجات > الاشتراكات).
- انقر على إنشاء اشتراك.
- أدخِل تفاصيل اشتراكك:
- ProductID : أدخِل معرّف منتج فريدًا. أدخِل
premium_plan. - الاسم : أدخِل اسمًا مختصرًا للاشتراك. مثال:
Premium Plan.
- ProductID : أدخِل معرّف منتج فريدًا. أدخِل
- انقر على إنشاء.
إنشاء "الخطة الأساسية"
- افتح Play Console وانتقِل إلى صفحة "الاشتراكات" (تحقيق الربح من خلال Play > المنتجات > الاشتراكات).
- انقر على السهم المتّجه لليسار بجانب الاشتراك الذي تريد إنشاء خطة أساسية فيه للاطّلاع على تفاصيل هذا الاشتراك.
- انقر على إضافة خطة أساسية.
- أدخِل معرّف الخطة الأساسية. مثال
monthly-auto-renewing - اختَر النوع تجديد تلقائي.
- بالنسبة إلى الخطة الأساسية التي تتجدّد تلقائيًا، اضبط ما يلي:
- مدة الفوترة: شهرية
- فترة السماح: 7 أيام
- التغييرات المتعلّقة بالعرض الترويجي وخطة الفوترة: التحصيل في تاريخ الفوترة
- إعادة الاشتراك: السماح
- في قسم السعر ومدى التوفّر، انقر على تحديد الأسعار لتحديد سعر الخطة الأساسية.
- اختَر جميع البلدان والمناطق، ثم انقر على تحديد السعر.
- اضبط السعر على 10 دولار أمريكي لهذه الخطة الأساسية، ثم انقر على تعديل.
- بعد ضبط سعر الخطة الأساسية، انقر على حفظ ثم على تفعيل في أسفل يسار الصفحة.
إنشاء اشتراكات للتطبيق النموذجي
لأغراض هذا الدرس التطبيقي حول الترميز، أنشئ اشتراكَين إضافيَين باستخدام الإعدادات التالية:
- الخطة الأساسية
- معرّف المنتج: basic_plan
- الاسم: الخطة الأساسية
- رقم تعريف الخطة الأساسية: monthly-auto-renewing
- السعر: $5
- خطة Lite
- معرّف المنتج: lite_plan
- الاسم: خطة Lite
- رقم تعريف الخطة الأساسية: monthly-auto-renewing
- السعر: $3
تم ضبط نموذج التطبيق لاستخدام معرّفات المنتجات ومعرّفات الخطة الأساسية هذه. يمكنك إنشاء اشتراكات مختلفة بإعدادات مختلفة، وفي هذه الحالة، عليك تعديل نموذج التطبيق لاستخدام معرّف المنتج الذي أنشأته.
فيديو حول إنشاء اشتراك
يعرض الفيديو التالي الخطوات الموضّحة سابقًا لإنشاء اشتراك في "وحدة تحكّم المطوّرين في Play".
4. عمليات استبدال الاشتراكات
يمكن للمطوّرين الذين يدمجون ميزة "الفوترة حسب الاستخدام" توفير خيارات مختلفة للمشتركين الحاليين لتغيير خطة الاشتراك بما يتناسب مع احتياجاتهم بشكل أفضل:
- إذا كنت تبيع فئات اشتراك متعددة، مثل اشتراكات أساسية ومميزة، يمكنك السماح للمستخدمين بالتبديل بين الفئات من خلال شراء خطة أساسية أو عرض لاشتراك مختلف.
- يمكنك السماح للمستخدمين بتغيير مدة الفوترة الحالية، مثل التبديل من خطة شهرية إلى خطة سنوية.
- يمكنك أيضًا السماح للمستخدمين بالتبديل بين خطط التجديد التلقائي وخطط الدفع المُسبَق.
عندما يقرّر المستخدمون الترقية أو الرجوع إلى إصدار أقدم أو تغيير اشتراكهم، عليك تحديد وضع الاستبدال الذي يحدّد كيفية تطبيق القيمة المقسَّمة لمدة الفوترة الحالية، وتحديد وقت حدوث تغيير الأهلية للمستخدمين.
توفّر "مكتبة الفوترة في Play" العديد من خيارات ReplacementMode للتحكّم في هذا السلوك.
أوضاع الاستبدال المتاحة
-
WITH_TIME_PRORATION: تتم ترقية أو الرجوع إلى إصدار سابق من السلعة التي تتضمّنها الاشتراك على الفور. ويتم تعديل أي وقت متبقٍ استنادًا إلى فرق السعر، وإضافته إلى الاشتراك الجديد من خلال تعديل تاريخ الفوترة التالي. هذا هو السلوك التلقائي. CHARGE_PRORATED_PRICE: تتم ترقية المنتج الذي تم الاشتراك فيه على الفور، وتبقى دورة الفوترة كما هي. بعد ذلك، يتم تحصيل فرق السعر من المستخدم عن الفترة المتبقية.CHARGE_FULL_PRICE: تتم ترقية أو خفض مستوى المنتج في الاشتراك على الفور، ويتم تحصيل السعر الكامل من المستخدم مقابل هذا الإذن الجديد على الفور. يتم إما نقل القيمة المتبقية من الاشتراك السابق إلى الاشتراك الجديد في الميزة نفسها، أو يتم تقسيمها بالتناسب مع الوقت عند التبديل إلى ميزة مختلفة.WITHOUT_PRORATION: تتم ترقية أو الرجوع إلى إصدار سابق من المنتج فورًا، ويتم تحصيل السعر الجديد عند تجديد الاشتراك. ستبقى دورة الفوترة كما هي.-
DEFERRED: تتم ترقية السلعة المتوفرة عند الاشتراك أو خفض مستواها عند تجديد الاشتراك فقط.
5- WITH_TIME_PRORATION
في وضع الاستبدال هذا، تتم ترقية المنتج الذي يتضمّنه الاشتراك أو خفض مستواه على الفور. ويتم تعديل أي وقت متبقٍ استنادًا إلى فرق السعر، وإضافته إلى الاشتراك الجديد من خلال تقديم تاريخ الفوترة التالي. هذا هو السلوك التلقائي.
مثال على السيناريو
يبدّل المستخدم من خطة أساسية (4.99 دولار أمريكي في الشهر) إلى خطة Premium (9.99 دولار أمريكي في الشهر) في 15 أبريل، أي في منتصف دورة الفوترة الشهرية.
في هذا السيناريو:
- يحصل المستخدم على الفور على إمكانية الوصول إلى خطة Premium.
- يحتسب Google Play تلقائيًا فترة التناسب. لنفترض أنّ Play احتسبت أنّ الأيام الـ 15 المتبقية من خطة Basic تساوي 7 أيام من خطة Premium، سيتم تقديم تاريخ الفوترة التالي إلى 21 أبريل.
- ليس على المستخدم دفع أي مبلغ على الفور.
مقتطف الرمز
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
الترقية باستخدام WITH_TIME_PRORATION
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- التبديل إلى خطة Premium
تتم ترقية إذن المستخدم إلى خطة Premium على الفور. المبلغ الذي سيدفعه المستخدم على الفور هو 0.00 دولار أمريكي. يتم احتساب القيمة المتبقية من خطة Basic بشكل نسبي وإضافتها إلى مدة خطة Premium، ما يؤدي إلى تقديم تاريخ التجديد التالي. سيتم تحصيل مبلغ التجديد البالغ 9.99 دولار أمريكي في تاريخ الفوترة المعدَّل حديثًا.
الرجوع إلى إصدار سابق باستخدام WITH_TIME_PRORATION
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- بدِّل إلى خطة Lite.
سيتم تخفيض مستوى اشتراك المستخدم إلى خطة Lite على الفور. المبلغ المطلوب دفعه على الفور هو 0.00 دولار أمريكي. يتم تقسيم القيمة المتبقية من خطة Basic بالتناسب مع الوقت المتبقي في خطة Lite، ما يؤدي إلى تمديد تاريخ التجديد التالي بشكل كبير. سيتم تحصيل مبلغ التجديد البالغ 2.99 دولار أمريكي من المستخدم في تاريخ الفوترة المعدَّل حديثًا.
الخاتمة
في هذا القسم، تعرّفت على كيفية تعديل WITH_TIME_PRORATION لأذونات المستخدمين بدون فرض رسوم فورية من خلال تعديل الوقت المتبقي حتى التجديد التالي استنادًا إلى فرق السعر. وهي استراتيجية تلقائية فعّالة لترقية المستخدمين أو الرجوع إلى إصدار سابق.
6. CHARGE_PRORATED_PRICE
في وضع الاستبدال هذا، تتم ترقية المنتج الذي تم استبداله في الاشتراك على الفور، وتبقى دورة الفوترة كما هي. بعد ذلك، يتم تحصيل فرق السعر من المستخدم عن الفترة المتبقية.
ملاحظة: لا يتوفّر هذا الخيار إلا لترقية منتج اشتراك، حيث يزداد السعر لكل وحدة زمنية.
مثال على السيناريو
قرّر مستخدم مشترك في خطة Basic (4.99 دولار أمريكي شهريًا) الترقية إلى خطة Premium (9.99 دولار أمريكي شهريًا) في 20 أبريل مع تبقّي 10 أيام تقريبًا في دورة الفوترة الشهرية.
في هذا السيناريو:
- يحصل المستخدم على الفور على إمكانية الوصول إلى خطة Premium.
- يتم على الفور تحصيل فرق السعر النسبي من المستخدم مقابل الأيام العشرة المتبقية من دورة الفوترة الحالية. يبلغ هذا المبلغ حوالي 2.99 دولار أمريكي، وهو يمثّل قيمة 10 أيام من خطة Premium.
- لا يتغيّر تاريخ الفوترة للمستخدم.
مقتطف الرمز
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
الترقية باستخدام CHARGE_PRORATED_PRICE
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- التبديل إلى خطة Premium
تتم ترقية المستخدم إلى خطة Premium على الفور، مع الاحتفاظ بتاريخ التجديد الأصلي. المبلغ المطلوب دفعه على الفور هو الفرق النسبي بين أسعار خطتَي Premium وBasic للأيام المتبقية من الدورة الحالية. في تاريخ التجديد، سيتم تحصيل مبلغ التجديد الكامل لاشتراك Premium البالغ 9.99 دولار أمريكي من المستخدم.
خفض مستوى الاشتراك باستخدام CHARGE_PRORATED_PRICE
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- بدِّل إلى خطة Lite.
يؤدي وضع الاستبدال هذا إلى حدوث خطأ أثناء الرجوع إلى إصدار أقدم لأنّه لا يتوفّر إلا لترقيات عناصر الاشتراك التي يزداد فيها السعر لكل وحدة زمنية. سيتعذّر إكمال عملية الفوترة وسيظهر للمستخدم خطأ يشير إلى أنّ وضع التسوية النسبية غير متاح لعمليات خفض مستوى الإصدار.
الخاتمة
يوضّح هذا القسم كيف تتيح ميزة CHARGE_PRORATED_PRICE إجراء ترقيات فورية من خلال تحصيل فرق السعر بالضبط من المستخدمين عن فترة الفوترة المتبقية مع الحفاظ على دورة الفوترة كما هي. يكون هذا الإجراء مفيدًا عندما يريد المستخدم الترقية إلى فئة سعرية أعلى بدون تغيير تاريخ الفوترة.
7. CHARGE_FULL_PRICE
في وضع الاستبدال هذا، تتم ترقية المنتج أو خفضه على الفور، ويتم تحصيل السعر الكامل من المستخدم مقابل الإذن الجديد على الفور. يتم إما نقل القيمة المتبقية من الاشتراك السابق إلى الاشتراك الجديد في الميزة نفسها، أو يتم تقسيمها بالتناسب مع الوقت عند التبديل إلى ميزة مختلفة.
مثال على السيناريو
يستخدم أحد الأشخاص خطة Basic (4.99 دولار أمريكي في الشهر بدءًا من 1 أبريل). في 20 أبريل، يريد المستخدم التبديل إلى خطة Premium (مقابل 9.99 دولار أمريكي شهريًا).
في هذا السيناريو:
- يتم تحصيل السعر الكامل لخطة Premium (9.99 دولار أمريكي) من المستخدم على الفور.
- يتم تحويل القيمة المتبقية من خطة Basic (على سبيل المثال، قيمة 10 أيام) إلى وقت مكافئ لخطة Premium. في هذا المثال، تعادل 10 أيام من الخطة الأساسية 5 أيام من الخطة المميزة.
- يتم تعديل تاريخ التجديد التالي للمستخدم ليشمل هذا الوقت النسبي. وبالتالي، يصبح تاريخ التجديد هو 25 مايو (20 أبريل + شهر واحد + 5 أيام).
- وسيتم تجديد الاشتراك شهريًا بدءًا من 25 أيار (مايو).
مقتطف الرمز
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
الترقية باستخدام CHARGE_FULL_PRICE
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- التبديل إلى خطة Premium
سيتم ترقية المستخدم إلى خطة Premium على الفور. المبلغ المطلوب دفعه فورًا هو السعر الكامل لخطة Premium البالغ 9.99 دولار أمريكي. يتم تحويل أي قيمة متبقية من خطة Basic إلى وقت في خطة Premium الجديدة، ما يؤدي إلى تمديد تاريخ التجديد الأول قليلاً. بعد ذلك، سيصبح مبلغ التجديد 9.99 دولار أمريكي لكل دورة.
الرجوع إلى إصدار أقدم مع CHARGE_FULL_PRICE
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- بدِّل إلى خطة Lite.
يتم خفض مستوى المستخدم إلى خطة Lite على الفور، وتبدأ دورة فوترة جديدة. المبلغ المطلوب دفعه فورًا هو السعر المستهدف الكامل البالغ 2.99 دولار أمريكي. يتم احتساب الجزء غير المستخدَم من الخطة الأساسية بالتناسب مع الوقت في خطة Lite الجديدة، ما يؤدي إلى تمديد تاريخ التجديد الأول. بعد ذلك، سيصبح مبلغ التجديد 2.99 دولار أمريكي لكل دورة.
الخاتمة
في هذا القسم، تناولنا كيفية تحصيل CHARGE_FULL_PRICE من المستخدم كامل المبلغ في يوم التبديل، وبدء دورة فوترة جديدة على الفور. يتم تطبيق أي رصيد متبقٍ من الخطة السابقة بشكل خطي على تاريخ التجديد التالي.
8. WITHOUT_PRORATION
في وضع الاستبدال هذا، تتم ترقية المنتج أو الرجوع إلى إصدار سابق منه على الفور، ويتم تحصيل السعر الجديد عند تجديد الاشتراك.
مثال على السيناريو
يستخدم أحد الأشخاص خطة Basic (4.99 دولار أمريكي في الشهر بدءًا من 1 أبريل). في 20 أبريل، يريد المستخدم التبديل إلى خطة Premium (مقابل 9.99 دولار أمريكي شهريًا).
في هذا السيناريو:
- يحصل المستخدم على الفور على إمكانية الوصول إلى خطة Premium.
- ولن يضطر المستخدم إلى دفع السعر الأعلى البالغ 9.99 دولار أمريكي حتى تاريخ تجديد الاشتراك التالي (1 أيار/مايو).
مقتطف الرمز
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
الترقية باستخدام WITHOUT_PRORATION
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- التبديل إلى خطة Premium
تتم ترقية المستخدم إلى خطة Premium على الفور مع الاحتفاظ بتاريخ التجديد الحالي. المبلغ المطلوب دفعه على الفور هو 0.00 دولار أمريكي. يمكن للمستخدم الاستفادة من خطة Premium خلال الوقت المتبقي في الدورة المحدّدة، قبل التبديل إلى مبلغ التجديد الجديد البالغ 9.99 دولار أمريكي في تاريخ الفوترة التالي.
الرجوع إلى إصدار سابق باستخدام WITHOUT_PRORATION
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- بدِّل إلى خطة Lite.
يتم خفض مستوى المستخدم إلى خطة Lite على الفور، ويفقد ميزات Basic التي دفع مقابلها. المبلغ المطلوب دفعه على الفور هو 0.00 دولار أمريكي. تستمر دورة الفوترة بدون تعديل، وسيدفع المستخدم السعر الجديد المخفَّض البالغ 2.99 دولار أمريكي عند التجديد المُجدوَل التالي.
الخاتمة
يوضّح هذا القسم كيف يتيح WITHOUT_PRORATION للمستخدم تبديل الأذونات على الفور بدون فرض رسوم على الدفع مع عدم تغيير دورة الفوترة.
9- DEFERRED
في وضع الاستبدال هذا، تتم ترقية عنصر الاشتراك أو الرجوع إلى إصدار سابق منه عند تجديد الاشتراك فقط، ولكن يتم إصدار عملية الشراء الجديدة على الفور. يتم ضبط المنتج الحالي على أنّه غير قابل للتجديد وتنتهي صلاحيته في نهاية دورة الفوترة الحالية، بينما يبدأ المنتج الجديد المطلوب بعد ذلك مباشرةً.
مثال على السيناريو
يستخدم أحد الأشخاص خطة Basic (4.99 دولار أمريكي في الشهر بدءًا من 1 أبريل). في 20 أبريل، يريد المستخدم التبديل إلى خطة Premium (مقابل 9.99 دولار أمريكي شهريًا).
في هذا السيناريو:
- لا يتحمّل المستخدم أي رسوم فورية.
- يستمر المستخدم في تلقّي ميزات Basic حتى نهاية دورة الفوترة الحالية (30 أبريل).
- تتم ترقية خطة الاشتراك تلقائيًا إلى Premium في تاريخ التجديد التالي (1 مايو).
مقتطف الرمز
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.DEFERRED;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
الترقية باستخدام DEFERRED
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- التبديل إلى خطة Premium
سيظل المستخدم مشتركًا في خطة Basic حتى نهاية دورة الفوترة الحالية. المبلغ المطلوب دفعه على الفور هو 0.00 دولار أمريكي. في تاريخ التجديد، ستتم ترقية اشتراكهم إلى خطة Premium وسيتم تحصيل مبلغ التجديد الجديد البالغ 9.99 دولار أمريكي.
الرجوع إلى إصدار سابق باستخدام DEFERRED
لمحاكاة هذا السيناريو، اتّبِع الخطوات التالية:
- في
MainActivityلنموذج التطبيق، عدِّلreplacementModeفي مقتطف الرمز إلىSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - أعِد إنشاء التطبيق وشغِّله.
- إلغاء الاشتراكات الحالية (إن وجدت) من "متجر Google Play" وانتهاء صلاحيتها
- اشترِ خطة Basic.
- بدِّل إلى خطة Lite.
سيظل المستخدم مشتركًا في خطة Basic حتى نهاية دورة الفوترة الحالية. المبلغ المطلوب دفعه على الفور هو 0.00 دولار أمريكي. في تاريخ التجديد، تتم ترقية أهليتهم إلى خطة Lite وسيتم تحصيل مبلغ التجديد الجديد البالغ 2.99 دولار أمريكي.
الخاتمة
يوضّح هذا القسم كيف يؤجّل وضع الاستبدال DEFERRED الترقية أو الرجوع إلى إصدار سابق حتى نهاية المدة الزمنية المدفوعة لمستخدم نشط. وهذا يجعلها مثالية بشكل خاص لخفض مستوى الاشتراك لتجنُّب فقدان الميزات التي تم شراؤها.
10. المعالجة من جهة الخلفية ومن جهة العميل
بعد أن يطلب المستخدم استبدال الاشتراك بنجاح، تأكَّد من أنّ تطبيقك والخادم الخلفي يتعاملان مع التغيير بشكل صحيح لتجنُّب مشاكل مثل انقطاع الخدمة أو الفوترة المزدوجة.
مثال على سيناريو
- لدى المستخدم خطة شهرية أساسية (product_id
basic_planوpurchase_tokenbasic_purchase_token_123). - ينتقل المستخدم إلى خطة Premium باستخدام وضع الاستبدال الفوري (أحد الخيارات التالية:
WITHOUT_PRORATIONأوWITH_TIME_PRORATIONأوCHARGE_PRORATED_PRICEأوCHARGE_FULL_PRICE) - بعد اكتمال عملية تبديل الاشتراك بنجاح، ستتعامل Google مع الاشتراك على أنّه اشتراك جديد وستنشئ رمزًا مميزًا جديدًا ومختلفًا للشراء في "الخطة المميزة" (product_id
premium_planوpurchase_tokenpremium_purchase_token_123).
المعالجة من جهة العميل
onPurchasesUpdated
عند اكتمال عملية الشراء البديلة، يتم تشغيل الحدث PurchasesUpdatedListener. على الرغم من أنّ هذا كان تبديلاً، يتعامل Google Play مع "الخطة المميزة" على أنّها عملية شراء جديدة تمامًا.
سيتلقّى التطبيق عنصر Purchase يحتوي على premium_purchase_token_123 رمز مميّز للشراء وproduct_id premium_plan. يجب التعامل مع هذا الرمز المميز تمامًا مثل المشترك الجديد: إثبات صحة الرمز المميز والاستعداد لمنح الإذن بالوصول
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {
for (Purchase purchase : purchases) {
// purchase.getPurchaseToken() = premium_purchase_token_123
// purchase.getProducts() will contain premium_plan
// Verify the purchase and grant entitlement
handleNewPurchase(purchase);
}
}
}
queryPurchasesAsync
لا تعرض الدالة queryPurchasesAsync سوى الاشتراكات النشطة التي تم شراؤها من تطبيقك. ويجب الاعتماد على هذه الطريقة لتحديد الأذونات التي يجب عرضها للمستخدم. بالنسبة إلى عمليات الاستبدال الفوري، ستتوقف queryPurchasesAsync() عن عرض رمز شراء BASIC القديم، ولن تعرض الآن سوى رمز شراء PREMIUM الجديد.
يجب استدعاء هذه الطريقة كلما استأنف تطبيقك العمل أو اكتملت عملية شراء. إذا كانت الرمز المميز لخطة Premium متوفّرة، يجب منح المستخدم على الفور ميزات Premium وإزالة ميزات Basic.
المعالجة في الخلفية (RTDN)
عند استبدال منتج، يرسل Google Play إشعارًا في الوقت الفعلي خاصًا بالمطوّرين (RTDN) إلى موضوع النشر/الاشتراك الذي تم إعداده.
- في حال الاستبدال الفوري، ترسل Google
SUBSCRIPTION_PURCHASEDإشعارًا في الوقت الفعلي للمطوّرين يتضمّن الرمز المميز الجديد لعملية الشراء.نموذج حمولة إشعار في الوقت الفعلي للمطوّرين{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - عندما يتلقّى الخادم الرمز المميز الجديد لعملية الشراء من RTDN، استدعِ واجهة برمجة التطبيقات
purchases.subscriptionsV2باستخدام الرمز المميز الجديد لعملية الشراء من أجل استرداد تفاصيل عملية الشراء. يحتوي ردّ واجهة برمجة التطبيقات على الحقلlinkedPurchaseTokenالذي يُستخدَم لتحديد ما إذا كان الرمز المميّز للشراء يشير إلى عملية شراء اشتراك جديد أو استبدال اشتراك. - في حال استبدال اشتراك، يشير
linkedPurchaseTokenإلى الرمز المميز لعملية شراء الاشتراك القديم. في هذا السيناريو، ستكون الإجابةbasic_purchase_token_123.SampleGET purchases.subscriptionsV2curl \ 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/<application_id>/purchases/subscriptionsv2/tokens/premium_purchase_token_123' \ --header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \ --header 'Accept: application/json' { "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "...", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", // The purchase token of the subscription that was replaced (Basic Plan in this case) "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // productID of the new subscription (Premium Plan in this case) "expiryTime": "....", "autoRenewingPlan": {...}, "offerDetails": { "basePlanId": "monthly-auto-renewing" // base plan ID of the new subscription }, "itemReplacement": { // Details about the subscription replacement "productId": "subscription_basic", // productID of the old subscription (Basic Plan in this case) "replacementMode": "CHARGE_PRORATED_PRICE", // Replacement strategy used for this subscription change "basePlanId": "monthly-auto-renewing" // base plan ID of the old subscription }, "offerPhase": {...} } ], "etag": "<etag_value>" } - يجب تأكيد عملية شراء اشتراك Premium الجديد. ويمكن إجراء ذلك إما داخل تطبيقك أو في الخلفية. في حال عدم تأكيد عملية الشراء خلال 3 أيام، سيتم ردّ الأموال وإلغاء الإذن. لمزيد من التفاصيل حول معالجة عمليات الشراء وإقرارها، يُرجى الرجوع إلى مستندات المطوّرين.
الخاتمة
تناول هذا القسم خطوات التعامل مع عمليات استبدال الاشتراكات الفورية على كلّ من تطبيق العميل والخادم الخلفي. علمت أنّ Google Play يتعامل مع الخطة الجديدة على أنّها عملية شراء جديدة تمامًا، ويصدر رمزًا مميزًا جديدًا لعملية الشراء. على العميل، يجب معالجة عملية الشراء الجديدة هذه باستخدام PurchasesUpdatedListener وتعديل الأذونات استنادًا إلى الردّ من queryPurchasesAsync. في الخلفية، عليك الاستماع إلى إشعارات SUBSCRIPTION_PURCHASED في الوقت الفعلي للرمز المميز الجديد، واستخدام واجهة برمجة التطبيقات purchases.subscriptionsv2 لتحديد linkedPurchaseToken الاشتراك القديم، وإبطال الوصول المرتبط بالرمز المميز القديم على الفور مع منح الإذن الجديد. يُرجى تذكُّر الموافقة على عملية الشراء الجديدة دائمًا.
11. معالجة عمليات الاستبدال المؤجّلة
على عكس أوضاع الاستبدال الفوري، يؤجّل الوضع ReplacementMode.DEFERRED تغيير الاشتراك وتعديل الأهلية إلى نهاية دورة الفوترة الحالية. تتطلّب معالجة عمليات الاستبدال المؤجّلة منطقًا محدّدًا لضمان حصول المستخدمين على الإذن المناسب في الوقت المناسب.
مثال على سيناريو
- لدى المستخدم خطة شهرية أساسية (product_id
basic_planوpurchase_tokenbasic_purchase_token_123) تتجدّد في 15 أبريل. - في 1 أبريل، يقرّر المستخدم التبديل إلى خطة Premium باستخدام
ReplacementMode.DEFERRED. - تنشئ Google رمز شراء جديدًا لخطة Premium (product_id
premium_planوpurchase_tokenpremium_purchase_123) على الفور، ولكن يتم تحديد موعد تحصيل المبلغ من المستخدم والاستحقاق في 15 أبريل.
معالجة الاستبدال المؤجّل
1. بعد نجاح مسار الشراء مباشرةً (التطبيق)
- يتم استدعاء
PurchasesUpdatedListenerبعد اكتمال مسار الشراء. سيتلقّى التطبيق عنصرPurchaseيحتوي على الرمز المميّز الجديد لعملية الشراءpremium_purchase_token_123، ومع ذلك سيظل product_id يشير إلىbasic_planالقديم لأنّ المستخدم لديه إذن استخدام الخطة الأساسية فقط. يجب التعامل مع هذا الرمز المميز تمامًا كما لو كان عملية شراء جديدة، ويجب إقراره.@Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // purchase.getPurchaseToken() = premium_purchase_token_123 // purchase.getProducts() will contain basic_plan // Verify and acknowledge the purchase handleNewPurchase(purchase); } } } - تعرض الدالة
queryPurchasesAsyncعملية الشراء مع الرمز المميّز الجديد لعملية الشراء (premium_purchase_token_123) على الفور، بالإضافة إلى إذن الوصول الأصلي (basic_plan) المرتبط بها. يمكنك الاعتماد على ذلك لمواصلة منح إذن استخدام خطة Basic للمستخدم.
2. بعد نجاح مسار الشراء مباشرةً (في الخلفية)
- يتم إرسال إشعار SUBSCRIPTION_PURCHASED في الوقت الفعلي الخاص بالمطوّرين (RTDN) فور انتهاء مسار شراء الرمز المميز الجديد (
premium_purchase_token_123).نموذج لحِزمة بيانات إشعار في الوقت الفعلي خاص بالمطوّرين{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - اتّصِل بالرمز
GET purchases.subscriptionsv2باستخدام الرمز المميّز الجديد لعملية الشراء من أجل استرداد تفاصيل عملية الشراء. يحتوي الردّ على بندَين.- أحدهما يمثّل الاشتراك القديم (الخطة الأساسية) ويتضمّن
expiryTimeفي المستقبل. لن يتم تجديد الاشتراك القديم، وسيحتوي علىdeferredItemReplacementيتضمّن الاشتراك الجديد (الخطة المدفوعة). يشير ذلك إلى استبدال مؤقت للاستحقاق القديم عند انتهاء صلاحيته. - تمثّل إحداهما الاشتراك الذي تم شراؤه حديثًا. لم يتم ضبط أي قيمة لـ expiryTime
{ "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "2026-05-07T15:50:11.383Z", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // Premium Plan has no expiry time "autoRenewingPlan": {...}, "offerDetails": {...}, "itemReplacement": {. // Subscription replacement details "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {} }, { "productId": "basic_plan", // Subscription to be replaced "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time in the future "autoRenewingPlan": {}, "offerDetails": {...}, "deferredItemReplacement": { // identifier indicating this subscription will be replaced upon renewal "productId": "subscription_premium" }, "latestSuccessfulOrderId": "GPA.<order_id>", "itemReplacement": {...}, } ], "etag": "<etag>" } - أحدهما يمثّل الاشتراك القديم (الخطة الأساسية) ويتضمّن
- يجب الموافقة على رمز الشراء الجديد. ويمكن إجراء ذلك إما داخل تطبيقك أو في الخلفية. لمزيد من التفاصيل حول معالجة عمليات الشراء وإقرارها، يُرجى الرجوع إلى مستندات المطوّرين.
- يتم إرسال SUBSCRIPTION_EXPIRED RTDN لرمز الشراء القديم (
basic_purchase_token_123).نموذج حمولة RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":13, // SUBSCRIPTION_EXPIRED "purchaseToken":"basic_purchase_token_123" //purchase token for the old subscription } } - عند استدعاء واجهة برمجة التطبيقات
GET purchases.subscriptionsv2باستخدام رمز الشراء القديم، سيظهر على أنّه منتهي الصلاحية (SUBSCRIPTION_STATE_EXPIRED). ويتم نقل إذن استخدام الخطة القديمة إلى عملية الشراء الجديدة للمدة المتبقية.
3- في تاريخ الاستبدال - أول تجديد بعد عملية الشراء (التطبيق)
- تعرض الدالة
queryPurchasesAsyncعملية الشراء مع الرمز المميز الجديد لعملية الشراء (premium_purchase_token_123) والاشتراك الجديد المرتبط به (premium_plan). - من المفترض أن يكون قد تمّت معالجة عملية الشراء الجديدة عند نجاح مسار الشراء، ولا عليك اتّخاذ أي إجراء خاص باستثناء التأكّد من منح المستخدم إذن الوصول إلى الاشتراك المناسب.
4. في تاريخ الاستبدال - التجديد الأول بعد مسار الشراء (الخادم الخلفي)
- باستخدام
ReplacementMode.DEFERRED، تتّبع عمليات التجديد الأولى السلوك العادي لأي عملية تجديد أخرى تتم فيها معالجةSUBSCRIPTION_RENEWEDإشعارات في الوقت الفعلي. ولن تحتاج إلى أي منطق خاص لعمليات الاستبدال عند حدوث ذلك. - اتّصِل بالرمز
GET purchases.subscriptionsv2باستخدام الرمز المميّز الجديد لعملية الشراء من أجل استرداد تفاصيل عملية الشراء. يحتوي الردّ على بندَين.- أحدهما يمثّل الاشتراك القديم (الخطة الأساسية) ويتضمّن
expiryTimeفي الماضي. لن تتضمّن الاشتراك القديم قيمة مضبوطة للحقلdeferredItemReplacement. - أحدهما يمثّل الاشتراك الجديد مع
expiryTimeفي المستقبل وتم ضبط الحقلautoRenewEnabledعلىtrue.
{ "kind": "androidpublisher#subscriptionPurchaseV2", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>..0", "linkedPurchaseToken": "basic_purchase_token_123", // purchase token of the old subscription "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // New subscription "expiryTime": "2026-05-07T16:00:09.437Z", // Expiry time set in the future "autoRenewingPlan": { "autoRenewEnabled": true, // Auto Renewing Flag set to True "recurringPrice": {...} }, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {. // Details of the subscription replacement "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {...} }, { "productId": "basic_plan", // Old subscription, Does not contains the deferredItemReplacement field "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time set in the past "autoRenewingPlan": {}, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {...}, } ], "etag": "<etag>" } - أحدهما يمثّل الاشتراك القديم (الخطة الأساسية) ويتضمّن
الخاتمة
يوضّح هذا القسم المعالجة الفريدة المطلوبة لـ ReplacementMode.DEFERRED. علمتَ أنّه على عكس الأوضاع الفورية، لا يحدث تغيير الأهلية إلا في نهاية دورة الفوترة الحالية. يتضمّن هذا القسم الخطوات اللازمة لكلّ من تطبيقك والخادم الخلفي لمعالجة عملية الشراء الأولية بشكلٍ صحيح، والإقرار بالرمز المميّز الجديد، وإدارة عملية تبديل الأذونات عند انتهاء صلاحية الاشتراك القديم وتفعيل الاشتراك الجديد.
12. Subscription Replacement Playground
تتيح لك ميزة ساحة تجارب الاستبدال في التطبيق النموذجي اختبار ترقية الاشتراكات وخفضها لمنتجات الاشتراك التي تم ضبطها في حسابك على Google Play Console. يوضّح هذا القسم كيفية استخدام ميزة ساحة تجارب الإعلانات البديلة.
الإعداد
لاستخدام ميزة استبدال الخلفية في "مساحة المرح"، تأكَّد مما يلي:
- يتطابق
packageIdفي ملفbuild.gradleمع التطبيق الذي تم إعداده في Google Play Console. - تم تسجيل حساب المستخدم التجريبي كمختبِر حائز على ترخيص في Google Play Console. لمزيد من المعلومات عن اختبار الترخيص، اطّلِع على مقالة اختبار إعداد الفوترة في تطبيقك.
Subscription Replacement Playground
يتضمّن نموذج التطبيق علامة التبويب ساحة تجارب الاستبدال التي تتيح لك محاكاة تغييرات الاشتراك. يمكنك طلب الاشتراكات المحدّدة في Play Console واختبار التبديل بينها باستخدام أوضاع استبدال مختلفة. تساعدك هذه البيئة التجريبية في فهم كيفية تأثير الأوضاع المختلفة في دورات الفوترة وأذونات اشتراكاتك، حتى تتمكّن من تحديد الخيارات الأنسب لاحتياجات نشاطك التجاري.
لمحاكاة عمليات الاستبدال باستخدام ساحة الألعاب، اتّبِع الخطوات التالية:
- انتقِل إلى علامة التبويب ساحة اللعب.
- إذا كان لديك اشتراك نشط: سيتم تمييزه. هذا هو الاشتراك الذي سيتم استبداله.

- إذا لم يكن لديك اشتراك نشط: عليك شراء اشتراك أولاً.
- تعرض قائمة Playground خطط Basic وPremium وLite التي تم إنشاؤها لهذا الدرس التطبيقي حول الترميز تلقائيًا.
- للاختبار باستخدام خطط أخرى تم ضبطها في Play Console، انقر على إضافة خطة مخصّصة، وابحث حسب
productIdوbasePlanId. - اشترِ الاشتراك المحدّد.
- من المفترض أن يظهر الآن الاشتراك النشط الذي اشتراه المستخدم حديثًا.

- اختَر الاشتراك المستهدف الذي يريد المستخدم التبديل إليه.
- اختَر وضع الاستبدال للانتقال.

- انقر على الزر اختبار الاستبدال لمحاكاة استبدال الاشتراك.
- ستظهر لك البطاقة السفلية لخدمة "الفوترة في Google Play" مع التفاصيل المحسوبة لعملية استبدال الاشتراك (مثل الرسوم الفورية وتعديلات دورة الفوترة).

- أكمِل المعاملة.
- انتقِل إلى صفحة إدارة الاشتراكات ضِمن تطبيق "متجر Play" للاطّلاع على التغييرات في الاشتراك النشط بالإضافة إلى تفاصيل حول تواريخ التجديد والأسعار المعدَّلة.

13. الخطوات التالية
- كيفية الاستفادة إلى أقصى حدّ من عملية دمج "الفوترة في Play"
- تذكَّر اتّباع أفضل الممارسات المتعلّقة بإثبات ملكية عمليات الشراء ومعالجتها على الخلفية الآمنة بعد أن يبدأ المستخدمون في شراء هذه المنتجات.
المستندات المرجعية
14. تهانينا
تهانينا! لقد نفّذت عمليات استبدال الاشتراكات بنجاح باستخدام أوضاع مختلفة لتحديد السعر النسبي، وأعددت عملية معالجة الخلفية لعمليات الانتقال بين الخطط.
ما تعلّمته
- كيفية ضبط
SubscriptionProductReplacementParamsباستخدام أوضاع استبدال محدّدة - الفرق بين عمليات الترقية الفورية وعمليات خفض المستوى المؤجّلة
- كيفية إيقاف رموز الاشتراك القديمة باستخدام
linkedPurchaseTokenمن خلال أرقام تعريف RTDN
الاستطلاع
نقدّر ملاحظاتك بشأن هذا الدرس العملي. يُرجى تخصيص بضع دقائق لإكمال الاستطلاع.