تنفيذ "الفوترة في Play" في تطبيق الويب التقدّمي

إذا كان تطبيق الويب التقدّمي مُدرَجًا في Google Play وأردت تحقيق الربح منه من خلال بيع منتجات داخل التطبيق أو الاشتراكات، ستتطلّب منك سياسة Play تنفيذ خدمة "الفوترة في Play". هناك واجهتا برمجة تطبيقات عليك تنفيذهما في تطبيق الويب التقدّمي، وهما Digital Goods API وPayment Request API.

Digital Goods API

Digital Goods API هي واجهة بين تطبيقك وGoogle Play. تتيح لك استرداد المنتجات الرقمية والتفاصيل التي أدخلتها لمنتجاتك داخل التطبيق واشتراكاتك في Play Console، بالإضافة إلى استرداد عمليات الشراء الحالية التي أجراها المستخدم. إذا لم تكن قد أضفت منتجات داخل التطبيق أو اشتراكات في Play Console بعد، احرص على اتّباع خطوات إعداد Play Console لنظام الفوترة في Play.

في 30 تشرين الثاني (نوفمبر) 2021، تم إصدار ChromeOS 96 مع تنفيذ الإصدار 2.0 من Digital Goods API.

انتهت مرحلة التجربة والتقييم للإصدار الأول من Digital Goods API في 30 يناير 2022. لذلك، تم إيقافها نهائيًا، ولا يتوفّر سوى الإصدار 2 من واجهة برمجة التطبيقات.

في 23 يونيو 2022، تم إصدار ChromeOS 103 مع تنفيذ الإصدار 2.1 من Digital Goods API. لا يتضمّن هذا الإصدار أي تغييرات غير متوافقة، بل يتضمّن طرقًا جديدة وحقولاً إضافية فقط: listPurchaseHistory() وitemType.

التسجيل في "التجربة الأصلية"

ملاحظة: تتوفّر حاليًا واجهة Digital Goods API من خلال التجربة الأصلية، وهي آلية تتيح للمطوّرين الوصول مبكرًا إلى واجهات Web API الجديدة. عليك التسجيل في التجربة الأصلية لواجهة برمجة التطبيقات Digital Goods API v2 وطلب رمز مميز، ثم تقديمه في أي صفحات في مصدرك.

عند التسجيل في التجربة الأصلية، سيظهر لك تاريخ "سارية حتى"، وهو التاريخ الذي يُضمن فيه عمل الرمز المميّز. يُرجى تذكُّر تجديد الرموز المميزة عند اقتراب هذا التاريخ لمواصلة المشاركة في الفترة التجريبية. تخضع واجهات برمجة التطبيقات التي يتم توفيرها كتجربة أصلية للتغيير، لذا احرص على البقاء على اطّلاع بأحدث التغييرات في أي تجربة أصلية تشارك فيها. في حال حدوث أي مشاكل، يُرجى الرجوع إلى مستندات Digital Goods API.

Payment Request API

تتولّى Payment Request API عملية الدفع الفعلية عند إجراء عملية شراء. تستخدِم هذه الواجهة تفاصيل المنتج التي توفّرها واجهة برمجة التطبيقات الخاصة بالسلع الرقمية لإجراء عملية الشراء داخل التطبيق باستخدام طريقة الدفع المناسبة، وهي في حالتنا "الفوترة في Google Play".

رصد ميزة Digital Goods API

يمكنك معرفة ما إذا كنت قد فعّلت واجهة برمجة التطبيقات بشكلٍ صحيح على موقعك الإلكتروني من خلال التجربة الأصلية عن طريق البحث عن طريقة getDigitalGoodsService في العنصر window.

if ('getDigitalGoodsService' in window) {
  // Digital Goods API is supported!
} else {
  console.log('DigitalGoodsService is not available.');
  // Use another payment method
}

الربط بخدمة الفوترة في Google Play

تم تصميم Digital Goods API ليكون متوافقًا مع مختلف المتصفّحات والمتاجر الرقمية، تمامًا مثلما أنّ Payment Request API لا يعتمد على المتصفّح ويمكن استخدامه مع مختلف مقدّمي خدمات الدفع. للحصول على مثيل للخدمة المرتبطة بميزة "الفوترة في Google Play"، مرِّر السلسلة "https://play.google.com/billing" كطريقة دفع إلى getDigitalGoodsService().

إذا عرضت الطريقة خطأً، لن تتوفّر طريقة الدفع في "خدمة الفوترة في Google Play" (على سبيل المثال، إذا كان المستخدم يصل إلى تطبيق الويب التقدّمي من خلال المتصفّح). بدلاً من ذلك، عليك توفير طريقة دفع أخرى لإجراء المعاملات.

if ('getDigitalGoodsService' in window) {
  // Digital Goods API is supported!
  try {
    const service = await window.getDigitalGoodsService('https://play.google.com/billing');
    // Google Play Billing service is available
  } catch (error) {
    // Google Play Billing service is not available. Use another payment flow.
  }
}

الحصول على تفاصيل المنتج

بعد ربط خدمة "السلع الرقمية" بخدمة Google Play، يمكنك استخدام واجهة برمجة التطبيقات لاسترداد معلومات حول المنتجات وعمليات الشراء.

تتيح لك الطريقة getDetails() الحصول على معلومات حول العناصر التي أعددتها في Play Console. يجب عرض معلومات مثل عنوان المنتج ووصفه وسعره للمستخدم في واجهة مستخدم تطبيقك ليعرف المنتجات المتاحة للشراء وسعرها.

ستحتاج الطريقة getDetails() إلى قائمة بمعرّفات العناصر التي تتوافق مع معرّفات المنتجات داخل التطبيق والاشتراكات التي أنشأتها في Play Console.

const itemDetails = await service.getDetails(['product_1', 'product_2', 'product_3']);
for (const item of itemDetails) {
  // Display item information to user
  displayItem(item.title, item.description, item.price);
}

للحصول على السعر المناسب للمنطقة المحلية للمستخدم، عليك إجراء بعض التنسيقات الإضافية:

const localePrice = new Intl.NumberFormat(navigator.language, {
  style: 'currency',
  currency: item.price.currency,
}).format(item.price.value);

ملاحظة: لا توفّر لك واجهة برمجة التطبيقات Digital Goods API طريقة للحصول على قائمة بمعرّفات السلع. بدلاً من ذلك، عليك إما ترميزها بشكل ثابت في تطبيقك أو استرجاعها من خادم الخلفية. تتيح لك واجهة Google Play Developer API الاستعلام عن قائمة أرقام تعريف المنتجات من الخلفية. (مزيد من المعلومات عن تنفيذ مكوّنات رئيسية في خدمة "الفوترة في Play" على خادم الخلفية بغض النظر عن الحل الذي تختاره، احرص على أن تكون أرقام تعريف العناصر متوافقة مع ما لديك في Play Console.

في الإصدار 2.1 من واجهة برمجة التطبيقات، يكون itemType أحد الحقول التي تعرضها getDetails(). وهي عبارة عن تعداد ثابت تكون فيه القيمة ”product” أو ”subscription” للإشارة إلى ما إذا كان العنصر المقابل منتجًا داخل التطبيق أو اشتراكًا على التوالي. يمكن أن يكون التمييز بين نوعَي المنتجات مفيدًا إذا كنت بحاجة إلى تطبيق معالجات مختلفة على كل نوع من أنواع المنتجات. على سبيل المثال، يمكنك تخصيص صفحة للمستخدمين للاشتراك وصفحة أخرى للمنتجات الأخرى غير المتوفّرة من خلال الاشتراك. ويفيد أيضًا في معرفة مصدر REST المناسب لواجهة Google Play Developer API الذي يجب استخدامه في الخلفية (purchases.products أو purchases.subscriptions).

شراء سلعة

بعد عرض منتجاتك وتفاصيلها للمستخدم، يمكنك إنشاء مسار الشراء باستخدام Payment Request API. عند استخدامها مع Digital Goods API، يجب توفير مَعلمة إدخال واحدة فقط: methodData.

لا يتيح نظام الفوترة في Play سوى شراء منتج واحد في كل مرة، ويعرف خادم Play مسبقًا سعر المنتج وتفاصيله، لذا لا حاجة إلى استخدام المَعلمة details. يمكنك الاطّلاع على الشرح للحصول على توضيح أكثر تفصيلاً.

استخدِم العنصر supportedMethods من المَعلمة methodData في PaymentRequest لتحديد "الفوترة في Google Play" كطريقة الدفع باستخدام السلسلة "https://play.google.com/billing". بعد ذلك، في العنصر data، مرِّر رقم تعريف المنتج كـ sku.

const paymentMethodData = [
  {
    supportedMethods: 'https://play.google.com/billing',
    data: {
      sku: item.itemId,
    },
  },
];

بعد ذلك، أنشئ طلب الدفع واستدعِ show() لبدء عملية الدفع:

const request = new PaymentRequest(paymentMethodData);
const paymentResponse = await request.show();

سيؤدي ذلك إلى عرض واجهة مستخدم الشراء على Play للمستخدم، حيث سيطّلع على تفاصيل المنتج الذي يحاول شراءه. ويمكنهم إما إلغاء المعاملة أو متابعة عملية الدفع. إذا ألغى المستخدم عملية الدفع، سيتم رفض الوعد الذي تم إرجاعه من خلال show() مع ظهور خطأ. إذا تمكّنوا من الدفع وإكمال عملية الشراء بنجاح، سيتم إكمال الوعد باستخدام PaymentResponse. في السمة details لرد الدفع، يتم عرض رمز مميّز لعملية الشراء.

لمنع الاحتيال، من المهم التحقّق من عملية الشراء ورمز الشراء المميز على خادم الخلفية. من المستحسن أيضًا تتبُّع المستخدمين ورموز الشراء المرتبطة بهم. كيفية تنفيذ عملية إثبات الملكية على خادم الخلفية

بعد التحقّق من صحة عملية الشراء، استدعِ الدالة complete() في ردّ الدفع لإنهاء مسار الدفع وإغلاق واجهة مستخدم الفوترة. يمكنك أيضًا إدخال السلسلة result الاختيارية للإشارة إلى حالة عملية الدفع. ويعود إلى المتصفّح تحديد ما إذا كان سيقدّم أي إشارة إلى المستخدم بشأن هذه النتيجة. لا ينشئ Chrome أي إشارات مرئية للمستخدم، لذا ننصحك بعرض رسائل الخطأ أو النجاح الخاصة بك في تطبيق الويب التقدّمي.

/* Changes were recently made so that the PaymentResponse `details` property returns the purchase token as `purchaseToken` instead of `token`. Note that `token` will be deprecated at some point in the future. To ensure that your app won't be affected by this, make the change to `purchaseToken` in your client code and use the latest version of Bubblewrap (v1.13.5 and later) to update and generate a new app package to upload to the Play Console. */
const { purchaseToken } = paymentResponse.details;

let paymentComplete;
if (validatePurchaseOnBackend(purchaseToken)) {
  paymentComplete = await paymentResponse.complete('success');
  // Let user know their purchase transaction has successfully completed and been verified
} else {
  paymentComplete = await paymentResponse.complete('fail');
  // Let user know their purchase transaction failed to verify
}

ترقية الاشتراكات والرجوع إلى إصدار سابق منها

وتكون خطوات عملية الشراء هذه هي نفسها لكلّ من المنتجات داخل التطبيق وعمليات شراء الاشتراكات. ومع ذلك، يوفّر Google Play خيارات شراء إضافية يمكنك تنفيذها للاشتراكات، وهي الترقية إلى خطة أعلى والاشتراك في خطة أقلّ كلفة. عند إنشاء data لطريقة الدفع، عليك إدخال ما يلي لبدء عملية الترقية أو الرجوع إلى إصدار سابق:

  • sku: هذا هو رقم تعريف السلعة للاشتراك الجديد الذي سيتم ترقيته أو خفضه.
  • oldSku: هذا هو رقم تعريف السلعة للاشتراك الحالي للمستخدم.
  • purchaseToken: هذا هو الرمز المميز لعملية الشراء الخاصة بالاشتراك الحالي للمستخدم. كما ذكرنا سابقًا، من المستحسن تتبُّع رموز الشراء المميزة في الخلفية. في هذه الحالة وغيرها، عليك ربط المستخدم بعمليات الشراء الحالية ورموز الشراء أيضًا.
  • prorationMode: هذه هي طريقة تحصيل رسوم الاشتراك الجديد عند استبدال الاشتراك الحالي للمستخدم.
وضع التوزيع النسبي الوصف

immediateAndChargeProratedPrice

تتم ترقية الاشتراك على الفور، وتبقى دورة الفوترة كما هي. بعد ذلك، يتم تحصيل فرق السعر من المستخدم عن الفترة المتبقية.

immediateAndChargeFullPrice

تتم ترقية الاشتراك أو الرجوع إلى خطة أقلّ كلفة ويتم تحصيل السعر الكامل لإذن الاستخدام الجديد من المستخدم على الفور. يتم توزيع القيمة المتبقية من الاشتراك السابق بالتناسب مع الوقت المتبقي للاشتراك الجديد. تمت إضافة وضع التسعير النسبي هذا مؤخرًا في الإصدار 4.0 من Google Play Billing Library. يتوفّر الآن من خلال Bubblewrap بدءًا من الإصدار 1.13.5.

immediateWithoutProration

تم إيقافها مؤقتًا: هناك مسار محتمل للاحتيال في وضع التسعير النسبي هذا، حيث يمكن للمستخدمين الحصول على اشتراك تمت ترقيته بدون دفع رسوم إضافية لدورة فوترة واحدة. يُرجى العلم أنّنا أوقفنا هذا الوضع مؤقتًا ريثما ننتهي من إصلاح المشكلة.

immediateWithTimeProration

تتم ترقية الاشتراك أو الرجوع إلى إصدار سابق منه على الفور. ويتم تعديل أي وقت متبقٍ استنادًا إلى فرق السعر، ويتم إضافته إلى الاشتراك الجديد من خلال تقديم تاريخ الفوترة التالي. وهذا هو السلوك التلقائي.

مؤجَّل

تتم ترقية الاشتراك أو الرجوع إلى إصدار سابق منه عند تجديده فقط. ويفيد ذلك بشكل خاص في عمليات الرجوع إلى إصدار أقدم.

unknownSubscriptionUpgradeDowngradePolicy

ما مِن سياسة محدّدة. ولا ننصح بذلك.

يمكنك الاطّلاع على مزيد من المعلومات عن أوضاع التناسب المختلفة في المستندات المرجعية الخاصة بمكتبة الفوترة في Google Play. يمكنك الاطّلاع على مستندات مطوّري تطبيقات Android لمعرفة المزيد حول ترقية الاشتراكات وخفضها واقتراحات وضع التناسب.

سيبدو استخدام هذه الحقول الإضافية على النحو التالي:

const paymentMethod = [
  {
    supportedMethods: 'https://play.google.com/billing',
    data: {
      sku: item.itemId,
      oldSku: oldPurchase.itemId,
      purchaseToken: oldPurchase.purchaseToken,
      prorationMode: 'immediateAndChargeProratedPrice',
    },
  },
];

في هذا المثال، item هو ItemDetails للاشتراك الجديد الذي يحاول المستخدم الترقية إليه أو الرجوع إلى إصدار سابق منه، وoldPurchase هو PurchaseDetails للاشتراك الحالي للمستخدم.

الإقرار بعملية شراء

بعد أن يشتري المستخدم سلعة، عليك منحه الأذونات المناسبة (الوصول إلى السلعة أو المحتوى الذي اشتراه). بعد ذلك، أكِّد عملية الشراء. يُعلم الإقرار بعملية شراء Google Play بأنّك تلقّيت عملية الشراء وعالجتها بشكل مناسب.

ملاحظة: إذا لم يتم الإقرار بإتمام عملية شراء في غضون 72 ساعة من وقت الشراء، سيتم ردّ الأموال إلى المستخدم وإلغاء عملية الشراء. لن يعود رمز الشراء المميز صالحًا، لذا عند الاستعلام عن عمليات الشراء الحالية، لن يتم عرض عملية الشراء التي تم إبطالها. ويضمن ذلك عدم تحصيل رسوم من المستخدم بشكل غير صحيح في حال حدوث خطأ في الشبكة يؤدي إلى عدم منح إذن استخدام السلعة.

عليك الإقرار بعمليات الشراء من خادم الخلفية باستخدام Google Play Developer API. ننصحك بمنح الأذونات ثم تأكيد عملية الشراء معًا في خادم الخلفية.

  1. بعد أن يجري المستخدم عملية شراء من جهة العميل، أرسِل الرمز المميّز لعملية الشراء ومعرّف المنتج في طلب إلى خادم الخلفية.
  2. في الخلفية، للحصول على تفاصيل حول عملية الشراء من أجل إثبات صحتها، اتّصِل بما يلي:
  3. امنح المستخدم الإذن المناسب في قاعدة البيانات الخلفية.
  4. بعد ذلك، أكِّد عملية الشراء من خلال الاتصال على:

استهلاك عملية شراء

عند إقرار عملية شراء، يتم إعلام Google Play بأنّ المستخدم يملك السلعة الآن ويجب ألا يُسمح له بشرائها مرة أخرى. إذا كان هذا المنتج سيشتريه المستخدم مرة واحدة فقط وسيملكه إلى الأبد (مثل مظهر شخصية في لعبة)، لن يكون المنتج قابلاً للاستهلاك.

بدلاً من ذلك، قد يكون المنتج شيئًا لا تسمح للمستخدم إلا بالحصول على نسخة واحدة منه في المرة الواحدة. بعد ذلك، يجب أن يستخدم المنتج قبل أن يتمكّن من شراء منتج آخر. عندما "يستخدم" المستخدم المنتج، يجب استدعاء الطريقة consume() لإعلام Google Play بأنّ المستخدم قد استهلك المنتج. سيُتيح Google Play بعد ذلك للمستخدم شراء المنتج مرة أخرى.

بالنسبة إلى السلع التي تسمح للمستخدم بامتلاك نسخ متعددة منها، يجب أن يكون بالإمكان شراؤها بشكل متكرر بدون الحاجة إلى استخدامها أولاً (نسمّي هذه السلع سلعًا قابلة للتكرار). وبالمثل، يجب "استهلاك" هذه العناصر قبل أن يسمح Google Play للمستخدم بشرائها مرة أخرى. لذلك، حتى إذا لم يستخدم المستخدم المنتج بعد، عليك استدعاء الطريقة consume() لوضع علامة على المنتج باعتباره مستهلكًا.

// After the user purchases the item, send the purchase token and item ID to your backend to grant the entitlement and acknowledge it right away

. . .
// When the user uses the item or if it is a repeatable item, consume it so it’s available for purchase again.
service.consume(purchaseToken);
}

التحقّق من عمليات الشراء الحالية

آخر مسار رئيسي للمستخدم هو التحقّق من عمليات الشراء الحالية (المنتجات داخل التطبيق التي لم يتم استهلاكها بعد والاشتراكات الجارية) لإعلام المستخدمين بالاشتراك أو العناصر التي يملكونها حاليًا. ستكون عمليات الشراء الحالية هذه من عمليات شراء سابقة على Google Play على أي جهاز تم إجراؤها داخل التطبيق أو على "متجر Play". تُعرف عمليات الشراء التي يتم إجراؤها من خارج التطبيق في "متجر Play" باسم عمليات الشراء خارج التطبيق.

عند استرداد عمليات الشراء الحالية، عليك أيضًا التحقّق من حالة الإقرار واسترداد أي عمليات شراء تم إجراؤها سابقًا ولكن لم يتم الإقرار بها بشكل صحيح. يُنصح بإرسال إقرار باستلام عمليات الشراء في أقرب وقت ممكن لضمان أن تكون امتيازات المستخدم محدّثة وموضّحة بشكل صحيح في التطبيق.

ستعرض طريقة Digital Goods API listPurchases() قائمة PurchaseDetails تتضمّن itemId وpurchaseToken لكل عملية شراء. عليك استخدام واجهة Google Play Developer API على خادم الخلفية للتحقّق من حالة عمليات الشراء والإقرار بها على النحو المناسب. عليك إجراء ما يلي:

  1. استدعِ طريقة Digital Goods API listPurchases() من جهة العميل لاسترداد قائمة المشتريات الخاصة بالمستخدم.
  2. لكل عملية شراء، أرسِل purchaseToken وitemId إلى الخلفية.
  3. إذا كان ذلك مناسبًا، امنح المستخدم إذن الوصول في قاعدة البيانات الخلفية.
  4. ثم اتّصِل بـ:وتحقّق من acknowledgementState.
  5. إذا كانت القيمة 0 (لم يتم إقرارها بعد)، اتّصِل بما يلي:

مزيد من المعلومات حول كيفية التحقّق من عمليات الشراء على خادم الخلفية قبل منح الأذونات

سجل الشراء

في حين أنّ الدالة listPurchases ستعرض معلومات عن عمليات الشراء الحالية للمستخدم، ستعرض الدالة listPurchaseHistory() (في الإصدار 2.1 من واجهة برمجة التطبيقات) أحدث عملية شراء أجراها المستخدم لكل منتج، بغض النظر عمّا إذا كانت عملية الشراء منتهية الصلاحية أو تم إلغاؤها أو استهلاكها. تعرض الطريقة listPurchaseHistory() قائمة PurchaseDetails تحتوي على itemId وpurchaseToken لكل عملية شراء، ويجب استخدامها مع Google Play Developer API على خادم الخلفية لاسترداد المزيد من المعلومات.

عمليات الشراء خارج التطبيق

عمليات الشراء خارج التطبيق هي عمليات شراء لا تتم في مسار عمليات الشراء العادية داخل التطبيق. وعادةً ما تحدث هذه العمليات في "متجر Play" بدلاً من تطبيقك. هناك طريقتان رئيسيتان يمكن للمستخدمين من خلالهما إجراء عملية شراء خارج التطبيق:

  • استخدام رمز ترويجي: في قائمة مستخدمي "متجر Play"، ضمن "العروض والإشعارات" -> "استخدام رمز ترويجي" أو ضمن "الدفعات والاشتراكات" -> "استخدام رمز هدية"
  • إعادة الاشتراك: في قائمة المستخدمين في "متجر Play"، ضمن "الدفعات والاشتراكات" -> "الاشتراكات"، يمكن للمستخدمين إدارة جميع اشتراكاتهم في مختلف التطبيقات. بالنسبة إلى الاشتراكات المنتهية الصلاحية أو الملغاة، يتوفّر للمستخدمين خيار "إعادة الاشتراك".

عندما يعيد المستخدمون الاشتراك من "متجر Play"، لا يتم الإقرار بعمليات الشراء تلقائيًا، ما قد يؤدي إلى ردّ الأموال إليهم. هذا السلوك مقصود لأنّه لا يجب تحصيل رسوم الاشتراك من المستخدمين إلا إذا فتحوا التطبيق لاستخدامه. قد تظهر للمستخدم رسالة "تأكيد الاشتراك" على النحو التالي، لتذكيره بفتح التطبيق.

يُطلب من المستخدمين تأكيد اشتراكهم من خلال فتح التطبيق للإقرار بعملية الشراء.

ويقع على عاتقك كمطوّر تنفيذ الإقرار بهذه العمليات عند فتح المستخدم للتطبيق. ولهذا السبب، ننصحك بالتحقّق من عمليات الشراء الحالية (عادةً عند فتح التطبيق لأول مرة) والإقرار بأي عمليات شراء لم يتم الإقرار بها بعد.

السماح للمستخدمين بإدارة الاشتراكات

لتقديم تجربة جيدة للمستخدمين، من المهم توفير طريقة لهم لإدارة اشتراكاتهم وإلغائها داخل التطبيق. ننصحك بإنشاء رابط لصفحة معيّنة، في صفحة الإعدادات أو القائمة، يؤدي إلى إعادة توجيه المستخدم إلى صفحة إدارة الاشتراكات في تطبيقك على "متجر Play". استبدِل عنوان URL التالي بـ "sub-product-id" و"app-package-name" المناسبَين:

https://play.google.com/store/account/subscriptions?sku=sub-product-id&package=app-package-name

الخطوات التالية

تُعدّ مسارات المستخدمين ومقتطفات الرموز البرمجية هذه عملية تنفيذ أساسية لتوضيح كيفية استخدام واجهة برمجة التطبيقات Digital Goods API وواجهة برمجة التطبيقات Payment Request API في تطبيق الويب التقدّمي لتنفيذ خدمة "الفوترة في Play". عليك استخدام واجهات برمجة التطبيقات بالطريقة المناسبة لسياق تطبيقك وحالات استخدامه. للاطّلاع على مثال على عملية تنفيذ شاملة، يمكنك مراجعة نموذجنا المفتوح المصدر.

بعد ذلك، اطّلِع على كيفية تنفيذ عناصر مهمة من "الفوترة في Play" في خادم الخلفية للحفاظ على أمان تطبيقك وتحديثه دائمًا بحقوق المستخدم.