يوضّح هذا الموضوع كيفية دمج Google Play Billing Library في تطبيقك لبدء بيع المنتجات.
مدة الشراء
في ما يلي مسار شراء نموذجي لعملية شراء لمرة واحدة أو اشتراك.
- اعرض للمستخدم ما يمكنه شراؤه.
- ابدأ مسار الشراء ليتمكّن المستخدم من قبول عملية الشراء.
- أثبِت صحة عملية الشراء على الخادم.
- قدِّم المحتوى للمستخدم.
- الإقرار بتسليم المحتوى بالنسبة إلى المنتجات الاستهلاكية، يجب أن الشراء حتى يتمكن المستخدم من شراء العنصر مرة أخرى.
يتم تجديد الاشتراكات تلقائيًا إلى أن يتم إلغاؤها. يمكن أن يعمل الاشتراك من خلال الحالات التالية:
- نشط: المستخدم في وضع جيد ويمكنه الوصول إلى الاشتراك.
- ملغى: يشير هذا الرمز إلى أنّ المستخدم ألغى الاشتراك ولكن لا يزال بإمكانه الوصول إلى التطبيق حتى انتهاء صلاحيته.
- في فترة السماح: واجه المستخدم مشكلة في الدفع ولكن لا يزال بإمكانه الوصول. أثناء إعادة محاولة استخدام طريقة الدفع من قِبل Google
- معلّق: يشير ذلك إلى أنّ المستخدم واجه مشكلة في الدفع ولم يعُد بإمكانه الوصول إلى الملف أثناء. تحاول Google استخدام طريقة الدفع من جديد.
- متوقف مؤقتًا: أوقف المستخدم إمكانية الوصول مؤقتًا ولا يمكنه الوصول حتى يتم سيرته الذاتية.
- منتهي الصلاحية: ألغى المستخدم الاشتراك وفقد إمكانية الوصول إليه. تشير رسالة الأشكال البيانية يُعتبر المستخدم متوقفًا عن الاستخدام عند انتهاء الصلاحية.
إعداد الاتصال بـ Google Play
إنّ الخطوة الأولى لدمج الخدمة مع نظام الفوترة في Google Play هي إضافة Google Play Billing Library (مكتبة الفوترة في Google Play) مع تطبيقك وبدء عملية الربط.
إضافة الموارد التابعة لـ Google Play Billing Library
يُرجى إضافة الاعتمادية على Google Play Billing Library إلى build.gradle
في تطبيقك.
على النحو الموضّح:
Groovy
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing:$billing_version") }
إذا كنت تستخدم لغة Kotlin، تتضمّن وحدة KTX في Google Play Billing Library
دعم إضافات Kotlin والكوروتينات التي تمكّنك من كتابة نص اصطلاحي
لغة Kotlin عند استخدام Google Play Billing Library. لتضمين هذه
الإضافات في مشروعك، فأضِف التبعية التالية إلى
ملف واحد (build.gradle
) كما هو موضّح:
Groovy
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
إعداد عميل BillingClient
بعد إضافة واجهة اعتماد على "مكتبة الفوترة في Google Play"، ستحتاج إلى
لإعداد مثيل BillingClient
. BillingClient
هو العنصر الرئيسي
واجهة الاتصال بين Google Play Billing Library
بقية التطبيق. توفّر ميزة "BillingClient
" طرق ملائمة ومتزامنة
وغير المتزامنة في العديد من عمليات الفوترة الشائعة. ننصح بشدة
لديك اتصال واحد نشط من BillingClient
مفتوح في كل مرة
تجنَّب عمليات استدعاء PurchasesUpdatedListener
متعددة لحدث واحد.
لإنشاء BillingClient
، استخدِم newBuilder()
. يمكنك تمرير أي سياق
على newBuilder()
، ويستخدمها BillingClient
للحصول على سياق للتطبيق.
وهذا يعني عدم القلق بشأن تسرُّب الذاكرة. لتلقي تحديثات عن
عمليات الشراء، يجب أيضًا الاتصال بـ setListener()
، مع تمرير إشارة إلى
PurchasesUpdatedListener
يتلقّى هذا المستمع آخر الأخبار لجميع
عمليات الشراء في تطبيقك.
Kotlin
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
Java
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build();
الاتصال بـ Google Play
بعد إنشاء BillingClient
، ستحتاج إلى إنشاء اتصال بـ
Google Play.
للربط بمتجر Google Play، يُرجى الاتصال على الرقم startConnection()
. الاتصال
غير متزامنة، ويجب تنفيذ
BillingClientStateListener
لتلقي معاودة الاتصال بعد إعداد
العميل مكتمِلة وأنه جاهز لتقديم المزيد من الطلبات.
وعليك أيضًا تنفيذ منطق إعادة المحاولة للتعامل مع الاتصالات المفقودة مع Google Play.
لتنفيذ منطق إعادة المحاولة، عليك إلغاء onBillingServiceDisconnected()
.
وتأكَّد من أنّ BillingClient
يستدعي
startConnection()
لإعادة الاتصال بـ Google Play قبل الإنشاء
والطلبات الإضافية.
يوضح المثال التالي كيفية بدء اتصال واختبار أنه جاهزة للاستخدام:
Kotlin
billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(billingResult: BillingResult) { if (billingResult.responseCode == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } override fun onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } })
Java
billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // The BillingClient is ready. You can query purchases here. } } @Override public void onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. } });
عرض المنتجات المتوفّرة للشراء
بعد إنشاء اتصال بـ Google Play، ستتمكن من الاستعلام عن منتجاتك المتوفّرة وعرضها على المستخدمين
يُعتبر الاستعلام عن تفاصيل المنتج خطوةً مهمة قبل عرض المنتجات إلى المستخدمين، لأنّها تعرض معلومات محلية عن المنتجات بالنسبة الاشتراكات، تأكَّد من أنّ عرض منتجك يتوافق مع جميع سياسات Play.
لطلب الحصول على تفاصيل المنتجات داخل التطبيق، يمكنك الاتصال بالرقم queryProductDetailsAsync()
.
لمعالجة نتيجة العملية غير المتزامنة، يجب أيضًا تحديد
أداة معالجة البيانات التي تنفّذ واجهة ProductDetailsResponseListener
.
يمكنك بعد ذلك إلغاء onProductDetailsResponse()
، ما يؤدي إلى إشعار
المستمع عند انتهاء الاستعلام، كما هو موضح في المثال التالي:
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, productDetailsList -> // check billingResult // process returned productDetailsList }
Java
QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build(); billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { // check billingResult // process returned productDetailsList } } )
عند الاستعلام عن تفاصيل المنتج، مرر مثيل
QueryProductDetailsParams
تحدّد قائمة بسلاسل معرّفات المنتجات
تم إنشاؤه في Google Play Console إلى جانب ProductType
. تشير رسالة الأشكال البيانية
يمكن أن تكون قيمة السمة ProductType
إما ProductType.INAPP
للمنتجات التي يتم تحصيل سعرها مرة واحدة أو
ProductType.SUBS
للاشتراكات.
الاستعلام باستخدام إضافات Kotlin
إذا كنت تستخدم إضافات Kotlin، يمكنك طلب البحث عن منتج داخل التطبيق.
التفاصيل من خلال استدعاء دالة الإضافة queryProductDetails()
.
يستفيد queryProductDetails()
من الكوروتينات في لغة Kotlin بحيث لا تكون هناك حاجة
تحديد مستمع منفصل. بدلاً من ذلك، يتم تعليق الدالة حتى يتم تنفيذ الاستعلام
المكتملة، وبعدها يمكنك معالجة النتيجة:
suspend fun processPurchases() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("product_id_example")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)
// leverage queryProductDetails Kotlin extension function
val productDetailsResult = withContext(Dispatchers.IO) {
billingClient.queryProductDetails(params.build())
}
// Process the result.
}
في حالات نادرة، لا تتوافق بعض الأجهزة مع ProductDetails
queryProductDetailsAsync()
، عادةً بسبب إصدارات قديمة من Google Play
الخدمات: لضمان الدعم المناسب لهذا السيناريو، تعرف على كيفية استخدام
ميزات التوافق مع الإصدارات القديمة في نقل البيانات إلى الإصدار 5 من Play Billing Library
الدليل.
معالجة النتيجة
تخزّن Google Play Billing Library نتائج طلب البحث في List
من
كائنات ProductDetails
. ويمكنك بعد ذلك استدعاء طرق متنوعة لكل
عنصر واحد (ProductDetails
) في القائمة لعرض المعلومات ذات الصلة بالمنتج داخل التطبيق.
المنتج، مثل سعره أو وصفه. لعرض تفاصيل المنتجات المتوفّرة
لمزيد من المعلومات، يُرجى الاطّلاع على قائمة الطرق في الفئة ProductDetails
.
قبل عرض عنصر للبيع، تحقق من أن المستخدم لا يملك عنصر واحد. إذا كان لدى المستخدم عنصر مستهلك لا يزال في مكتبة العناصر الخاصة به، أن يستفيد من السلعة قبل أن يتمكّن من شرائها مرة أخرى
قبل توفير اشتراك، تأكَّد من أنّ المستخدم غير مشترك بعد. يُرجى أيضًا مراعاة ما يلي:
- تُرجع "
queryProductDetailsAsync()
" تفاصيل المنتَج المتوفّر عند الاشتراك بالإضافة إلى 50 عرضًا كحد أقصى لكل اشتراك - لا تعرض
queryProductDetailsAsync()
سوى العروض التي يجرّبها المستخدم مؤهل. إذا حاول المستخدم شراء عرض له غير مؤهَّلة (على سبيل المثال، إذا كان التطبيق يعرض قائمة قديمة من عروض مؤهّلة)، يخبر Play المستخدم بأنه غير مؤهَّل يمكن للمستخدم اختيار شراء الخطة الأساسية بدلاً من ذلك.
بدء مسار الشراء
لبدء طلب شراء من تطبيقك، يُرجى الاتصال بالرقم launchBillingFlow()
.
من سلسلة التعليمات الرئيسية لتطبيقك. تأخذ هذه الطريقة إشارة إلى
BillingFlowParams
الذي يحتوي على العنصر
تم الحصول على كائن ProductDetails
من خلال الاتصال.
queryProductDetailsAsync()
لإنشاء عنصر BillingFlowParams
، استخدِم
لفئة BillingFlowParams.Builder
.
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For One-time product, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For one-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call // ProductDetails.subscriptionOfferDetails() for a list of offers // that are available to the user. .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
تعرض الطريقة launchBillingFlow()
أحد رموز الاستجابة المتعددة المدرجة في
BillingClient.BillingResponseCode
احرص على التحقق من هذه النتيجة
والتأكد من عدم حدوث أي أخطاء عند بدء مسار الشراء. BillingResponseCode
من OK
تشير إلى نجاح عملية الإطلاق.
عند إجراء مكالمة ناجحة إلى launchBillingFlow()
، يعرض النظام رمز
تشغيل شاشة الشراء يعرض الشكل 1 شاشة شراء لأحد الاشتراكات:
يتصل Google Play بـ onPurchasesUpdated()
لعرض نتيجة عملية الشراء
العملية التي يتم إرسالها إلى مستمع ينفّذ PurchasesUpdatedListener
من واجهة pyplot. ويتم تحديد المستمع باستخدام طريقة setListener()
عندما
أعددت عميلك.
يجب تنفيذ onPurchasesUpdated()
للتعامل مع رموز الاستجابة المحتملة. تشير رسالة الأشكال البيانية
يوضح المثال التالي كيفية تجاهل onPurchasesUpdated()
:
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { handlePurchase(purchase) } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user cancelling the purchase flow. } else { // Handle any other error codes. } }
Java
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); } } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user cancelling the purchase flow. } else { // Handle any other error codes. } }
تؤدي عملية الشراء الناجحة إلى إنشاء شاشة نجاح عملية شراء على Google Play مشابهة الشكل 2.
تؤدي عملية الشراء الناجحة أيضًا إلى إنشاء رمز مميز للشراء، وهو عبارة عن معرّف يمثّل المستخدِم ومعرّف المنتج للمنتج داخل التطبيق اشتراه. ويمكن لتطبيقاتك تخزين الرمز المميز للشراء محليًا ننصحك بتمرير الرمز المميّز إلى خادم الخلفية الآمن حيث يمكنك لتأكيد عملية الشراء وحماية المستخدمين من الاحتيال. يتم وصف هذه العملية بشكل أكبر في القسم التالي.
ويتم أيضًا إرسال إيصال بالمعاملة عبر البريد الإلكتروني إلى المستخدم يحتوي على مُعرّف الطلب أو معرِّفًا فريدًا للمعاملة. يتلقّى المستخدمون رسالة إلكترونية تتضمّن مُعرّف طلب فريدًا. لكل عملية شراء لمنتج لمرة واحدة، وأيضًا للاشتراك الأولي عملية الشراء والتجديد التلقائي المتكرر لاحقًا يمكنك استخدام مُعرّف الطلب لإدارة عمليات ردّ الأموال في Google Play Console
تحديد سعر مخصّص
إذا كان من الممكن توزيع تطبيقك على المستخدمين في الاتحاد الأوروبي، استخدِم
طريقة واحدة (setIsOfferPersonalized()
) لإعلام المستخدمين بأنّ سعر السلعة كان
باستخدام أسلوب اتخاذ القرار المبرمج.
عليك الرجوع إلى Art. 6 (1) (على سبيل المثال) تقرير حقوق الطبع والنشر (CRD) من توجيه حقوق المستهلك 2011/83/EU لتحديد ما إذا كان السعر الذي تعرضه للمستخدمين هو مخصصة.
تستخدم الدالة setIsOfferPersonalized()
إدخالًا منطقيًا. عندما true
، تعرض واجهة مستخدم Play
الإفصاح. عندما false
، تحذف واجهة المستخدم بيان الإفصاح. الإعداد التلقائي
القيمة هي false
.
للمزيد من المعلومات، يُرجى زيارة مركز مساعدة المستهلكين.
جارٍ معالجة عمليات الشراء
وبعد أن يُكمل المستخدم عملية شراء، سيحتاج تطبيقك إلى معالجة عملية الشراء هذه.
في معظم الحالات، يتم إشعار تطبيقك بعمليات الشراء من خلال
PurchasesUpdatedListener
ومع ذلك، هناك حالات سيتم فيها حذف تطبيقك
الذين أدركوا عمليات الشراء من خلال الاتصال على الرقم BillingClient.queryPurchasesAsync()
كما هو موضح في جلب المشتريات.
بالإضافة إلى ذلك، إذا كان لديك برنامج إشعارات في الوقت الفعلي خاصة بالمطوّرين في
الخلفية الآمنة، يمكنك تسجيل عمليات شراء جديدة من خلال تلقي
subscriptionNotification
أو oneTimeProductNotification
للتنبيه بـ
عملية شراء جديدة. بعد تلقّي هذه الإشعارات، يُرجى الاتصال بفريق Google Play
Developer API للاطّلاع على الحالة الكاملة وتعديل حالة الواجهة الخلفية.
يجب أن يعالج تطبيقك عملية الشراء على النحو التالي:
- أثبِت صحة عملية الشراء.
- تقديم المحتوى للمستخدم والإقرار بتسليمه يمكنك اختياريًا وضع علامة "مستهلك" على السلعة حتى يتمكّن المستخدم من شرائها. مرة أخرى.
لتأكيد عملية شراء، يجب أولاً التأكّد من أنّ حالة الشراء معيّنة.
PURCHASED
إذا كانت عملية الشراء هي PENDING
، عليك معالجة
عملية الشراء على النحو الموضّح في التعامل مع المعاملات المعلَّقة. لعمليات الشراء
استلمتها من onPurchasesUpdated()
أو queryPurchasesAsync()
،
التحقق من عملية الشراء لضمان شرعيتها قبل أن يمنح التطبيق
الوصول. لمعرفة كيفية تأكيد عملية شراء بشكل صحيح، يمكنك الاطّلاع على صفحة تأكيد عمليات الشراء.
قبل منح الأذونات
بعد تأكيد عملية الشراء، يصبح تطبيقك جاهزًا لمنح أذونات الوصول إلى
المستخدم. يمكن تحديد حساب المستخدِم المرتبط بعملية الشراء من خلال
تم إرجاع ProductPurchase.obfuscatedExternalAccountId
من قِبل
Purchases.products:get
لعمليات شراء المنتجات داخل التطبيق
تم إرجاع SubscriptionPurchase.obfuscatedExternalAccountId
بواسطة
Purchases.subscriptions:get
للاشتراكات من جانب الخادم
obfuscatedAccountId
من Purchase.getAccountIdentifiers()
في
العميل، إذا تم تعيين واحد باستخدام setObfuscatedAccountId
عند
تم إجراء عملية الشراء.
بعد منح إذن الوصول إلى التطبيق، يجب أن يوافق تطبيقك على عملية الشراء. هذا النمط إقرار لإعلام Google Play بمنحك الوصول إلى الموقع الإلكتروني لعملية الشراء.
تعتمد عملية منح إذن الاستخدام والإقرار بعملية الشراء على ما إذا أن تكون عملية الشراء استهلاكًا أو غير قابل للاستهلاك أو باشتراك.
المنتجات الاستهلاكية
بالنسبة إلى المستهلكين، إذا كان لتطبيقك واجهة خلفية آمنة، ننصحك باستخدام
Purchases.products:consume
للاستفادة من عمليات الشراء بشكل موثوق. تأكد من أن
لم يتم استهلاك عملية الشراء من قبل من خلال الاطّلاع على consumptionState
من
نتيجة استدعاء Purchases.products:get
. إذا كان تطبيقك مخصّصًا للعملاء فقط
بدون خلفية، استخدِم consumeAsync()
من
مكتبة الفوترة في Google Play تلبّي كلتا الطريقتان الإقرار.
وتشير إلى أنّ تطبيقك منح المستخدم إذنًا بالوصول إلى البيانات.
وتسمح هذه الطرق أيضًا لتطبيقك لجعل المنتج الذي يتم تحصيل سعره مرة واحدة مناسبًا
رمز الشراء المُدخل المتاح لإعادة الشراء. معك consumeAsync()
يجب أيضًا تمرير كائن ينفذ ConsumeResponseListener
من واجهة pyplot. يعالج هذا العنصر نتيجة عملية الاستهلاك. يمكنك
إلغاء طريقة onConsumeResponse()
، التي
يتم إرسال طلبات البيانات إلى Google Play Billing Library عند اكتمال العملية.
يوضّح المثال التالي استهلاك منتج مع Google Play Billing Library باستخدام رمز الشراء المميّز المرتبط:
Kotlin
suspend fun handlePurchase(purchase: Purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener. val purchase : Purchase = ...; // Verify the purchase. // Ensure entitlement was not already granted for this purchaseToken. // Grant entitlement to the user. val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) } }
Java
void handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener. Purchase purchase = ...; // Verify the purchase. // Ensure entitlement was not already granted for this purchaseToken. // Grant entitlement to the user. ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // Handle the success of the consume operation. } } }; billingClient.consumeAsync(consumeParams, listener); }
المنتجات غير الاستهلاكية
للإقرار بعمليات الشراء غير القابلة للاستهلاك، إذا كان تطبيقك يحتوي على خلفية آمنة، يجب:
ننصحك باستخدام Purchases.products:acknowledge
للإقرار بتوفّرها بشكل موثوق.
عمليات الشراء. تأكّد من عدم الإقرار بعملية الشراء سابقًا من قِبل
جارٍ التحقّق من acknowledgementState
من نتيجة الاتصال
Purchases.products:get
إذا كان تطبيقك مخصّصًا للعملاء فقط، استخدِم BillingClient.acknowledgePurchase()
من
Google Play Billing Library في تطبيقك قبل الاعتراف
عملية شراء، يجب أن يتحقّق التطبيق مما إذا كان قد تمت الموافقة عليه من خلال استخدام
isAcknowledged()
في Google Play Billing Library.
يوضّح المثال التالي كيفية الإقرار بعملية شراء باستخدام مكتبة الفوترة في Google Play:
Kotlin
val client: BillingClient = ... val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ... suspend fun handlePurchase() { if (purchase.purchaseState === PurchaseState.PURCHASED) { if (!purchase.isAcknowledged) { val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) } } } }
Java
BillingClient client = ... AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ... void handlePurchase(Purchase purchase) { if (purchase.getPurchaseState() == PurchaseState.PURCHASED) { if (!purchase.isAcknowledged()) { AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener); } } }
الاشتراكات
يتم التعامل مع الاشتراكات بالطريقة نفسها التي يتم بها التعامل مع المنتجات غير الاستهلاكية. إذا أمكن، استخدم
Purchases.subscriptions.acknowledge
من
Google Play Developer API للإقرار باستلام عملية الشراء من خلال
خلفية آمنة. التأكّد من عدم الإقرار بعملية الشراء مسبقًا من قِبل
الاطّلاع على acknowledgementState
في مرجع الشراء من
Purchases.subscriptions:get
بخلاف ذلك، يمكنك الإقرار
اشتراكك باستخدام BillingClient.acknowledgePurchase()
من
Google Play Billing Library بعد التحقّق من isAcknowledged()
. الكل
يجب الموافقة على عمليات شراء الاشتراك الأولية. عمليات تجديد الاشتراكات
لا يلزم الإقرار بها. لمزيد من المعلومات حول موعد الاشتراكات
يجب الإقرار. يُرجى الاطّلاع على موضوع بيع الاشتراكات.
جارٍ جلب المشتريات
لا يمكن الاستماع إلى آخر الأخبار حول عمليات الشراء باستخدام PurchasesUpdatedListener
.
كافيًا لضمان معالجة تطبيقك لجميع عمليات الشراء. من المحتمل أن يكون
قد لا يكون التطبيق على دراية بجميع عمليات الشراء التي أجراها المستخدم. إليك بعض الأمثلة
السيناريوهات التي قد يفقد فيها تطبيقك تتبُّع عمليات الشراء أو لا يلاحظها:
- مشاكل في الشبكة أثناء عملية الشراء: يُجري مستخدم عملية شراء ناجحة.
يتلقّى تأكيدًا من Google، ولكن يقطع الجهاز الشبكة
إمكانية الاتصال قبل أن يتلقّى جهاز العميل إشعارًا بعملية الشراء
من خلال
PurchasesUpdatedListener
. - أجهزة متعدّدة: يشتري المستخدم سلعة على جهاز واحد، ثم يتوقّع ما يلي: العنصر عند تبديل الأجهزة.
- التعامل مع عمليات الشراء التي تم إجراؤها خارج تطبيقك: قد يتم إجراء بعض عمليات الشراء، مثل عمليات تحصيل قيمة العروض الترويجية، يمكنك إجراؤها خارج تطبيقك.
للتعامل مع هذه المواقف، تأكد من أن تطبيقك يستدعي
BillingClient.queryPurchasesAsync()
في طريقة onResume()
من أجل
تأكَّد من أنّه تمّت معالجة جميع المشتريات بنجاح على النحو الموضّح في المعالجة
عمليات الشراء.
يوضّح المثال التالي كيفية استرجاع عمليات شراء اشتراكات المستخدم.
لاحظ أن queryPurchasesAsync()
تعرض الاشتراكات النشطة فقط
عمليات الشراء التي تتم لمرة واحدة وغير الاستهلاكية
Kotlin
val params = QueryPurchasesParams.newBuilder() .setProductType(ProductType.SUBS) // uses queryPurchasesAsync Kotlin extension function val purchasesResult = billingClient.queryPurchasesAsync(params.build()) // check purchasesResult.billingResult // process returned purchasesResult.purchasesList, e.g. display the plans user owns
Java
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder() .setProductType(ProductType.SUBS) .build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse(BillingResult billingResult, List<Purchase> purchases) { // check billingResult // process returned purchase list, e.g. display the plans user owns } } );
التعامل مع عمليات الشراء التي تتم خارج تطبيقك
يمكن أن تتم بعض عمليات الشراء، مثل عمليات تحصيل قيمة العروض الترويجية، خارج تطبيقك. عندما يُجري المستخدم عملية شراء خارج تطبيقك، يتوقع ظهور تطبيقك. أو رسالة داخل التطبيق، أو استخدام نوع من آلية الإشعار للسماح للمستخدم معرفة أنّ التطبيق قد استلم عملية الشراء وعالجها بشكل صحيح بعضها مقبول والآليات التالية هي:
- عرض نافذة منبثقة داخل التطبيق
- أوصل الرسالة إلى مربع رسائل داخل التطبيق، مع الإشارة بوضوح إلى وجود هي رسالة جديدة في مربّع الرسائل داخل التطبيق.
- استخدام رسالة إشعار نظام التشغيل
يُرجى الأخذ في الاعتبار أنّه من الممكن أن يكون تطبيقك في أي حالة التعرف على عملية الشراء. من المحتمل أيضًا ألا يكون تطبيقك تم تثبيته عند إجراء عملية الشراء. يتوقّع المستخدمون تلقّي المحتوى الذي اشتريته. عند استئناف التطبيق، بغض النظر عن الحالة التي يوجد بها التطبيق.
يجب رصد عمليات الشراء بغض النظر عن الولاية التي يعمل فيها التطبيق. تم إجراء عملية الشراء. ومع ذلك، هناك بعض الاستثناءات التي قد تكون مقبولة. عدم إبلاغ المستخدم على الفور باستلام المنتج مثلاً:
- أثناء جزء الإجراء في اللعبة، وقد يؤدي عرض رسالة ما إلى تشتيت انتباه المستخدم. وفي هذه الحالة، يجب إبلاغ المستخدم بعد انتهاء جزء الإجراء.
- في المشاهد القصيرة، قد يؤدي عرض رسالة إلى تشتيت انتباه المستخدم في هذه الدورة، في هذه الحالة، يجب عليك إعلام المستخدم بعد انتهاء المشهد
- أثناء البرنامج التعليمي الأولي وأجزاء إعداد المستخدم من اللعبة. ننصحك بما يلي: إشعار المستخدمين الجدد بالمكافأة فور فتح اللعبة أو أثناء إعداد المستخدم الأولي. ومع ذلك، يمكن الانتظار حتى يتم عرض تسلسل الألعاب متاحًا لإبلاغ المستخدم.
ضع المستخدم في الاعتبار دائمًا عند تحديد وقت وكيفية إشعار المستخدمين
عمليات الشراء التي تمت خارج تطبيقك. أي وقت لا يتلقّى فيه المستخدم على الفور
إشعار، فقد يشعرون بالارتباك، وقد يتوقفون عن استخدام تطبيقك، ويتواصلون مع المستخدم
أو يدعمه أو يشتكي بشأنه على وسائل التواصل الاجتماعي. ملاحظة:
تم تسجيل PurchasesUpdatedListener
في طلبك.
السياق لمعالجة تعديلات الشراء، بما في ذلك عمليات الشراء التي بدأت خارج
لتطبيقك. وهذا يعني أنه في حالة عدم وجود عملية تقديم الطلب،
لن يتم إشعار PurchasesUpdatedListener
. لهذا السبب يجب أن
استدعاء BillingClient.queryPurchasesAsync()
بطريقة onResume()
باسم
مذكور في جلب عمليات الشراء.
التعامل مع المعاملات المعلّقة
يتيح Google Play المعاملات المعلّقة أو المعاملات التي تتطلّب معاملة أو المزيد من الخطوات الإضافية بين وقت بدء المستخدم عملية شراء ووقت بدء معالجة طريقة دفع عملية الشراء. يجب ألا يمنح تطبيقك حق الوصول إلى هذه الأنواع من عمليات الشراء إلى أن ترسل Google إليك إشعارًا تم تحصيل الرسوم من طريقة الدفع التي استخدمها المستخدم بنجاح.
على سبيل المثال، يمكن للمستخدم بدء معاملة عن طريق اختيار متجر حيث سيدفعون نقدًا لاحقًا. يتلقى المستخدم رمزًا من خلال كليهما والإشعار والبريد الإلكتروني. عندما يصل المستخدم إلى المتجر الفعلي، يمكنك تحصيل قيمة الرمز لدى الصرّاف والدفع نقدًا. بعد ذلك، ترسِل Google إشعارًا استلام الدفعة أنت والمستخدم يمكن لتطبيقك بعد ذلك منح المستخدم.
يمكنك استدعاء enablePendingPurchases()
كجزء من إعداد
BillingClient
لتفعيل المعاملات في انتظار المراجعة لتطبيقك. يجب أن
تفعيل المعاملات المعلَّقة ودعمها للمنتجات التي يتم تحصيل سعرها مرة واحدة قبل
إضافة دعم، واحرِص على فهم مراحل نشاط الشراء للحالة "في انتظار المراجعة"
المعاملات.
عندما يتلقّى تطبيقك عملية شراء جديدة، إما من خلال
PurchasesUpdatedListener
أو نتيجة اتصال
queryPurchasesAsync()
، استخدِم طريقة getPurchaseState()
من أجل
حدِّد ما إذا كانت حالة الشراء هي PURCHASED
أو PENDING
. عليك
منح حق الوصول فقط عندما تكون الولاية هي PURCHASED
.
إذا كان تطبيقك قيد التشغيل عندما يُكمل المستخدم عملية الشراء، يجب تنفيذ ما يلي:
تم استدعاء PurchasesUpdatedListener
مرة أخرى، وأصبح PurchaseState
الآن
PURCHASED
في هذه المرحلة، يمكن لتطبيقك معالجة عملية الشراء باستخدام
لمعالجة عمليات الشراء. من المفترض أن يتّصل التطبيق أيضًا
queryPurchasesAsync()
في طريقة onResume()
الخاصة بتطبيقك للتعامل مع عمليات الشراء
التي انتقلت إلى حالة PURCHASED
عندما لم يكن تطبيقك قيد التشغيل.
عند انتقال عملية الشراء من PENDING
إلى
PURCHASED
، يتلقّى عميلك إشعارات في الوقت الفعلي خاصة بالمطوّرين
ONE_TIME_PRODUCT_PURCHASED
أو
إشعار SUBSCRIPTION_PURCHASED
في حال إلغاء عملية الشراء، يجب
يتلقّى ONE_TIME_PRODUCT_CANCELED
أو
إشعار SUBSCRIPTION_PENDING_PURCHASE_CANCELED
يمكن أن يحدث هذا إذا كان
عدم إكمال العميل لعملية الدفع في الإطار الزمني المطلوب. لاحظ أنه
دائمًا استخدام Google Play Developer API للتحقق من حالة
عملية الشراء.
التعامل مع عمليات الشراء بكميات متعددة
تتوفّر هذه الميزة في الإصدار 4.0 والإصدارات الأحدث من Google Play Billing Library. يتيح Google Play للعملاء شراء أكثر من عنصر واحد داخل التطبيق نفسه. منتج في معاملة واحدة عن طريق تحديد كمية من عربة الشراء. من المتوقّع أن يعالج التطبيق عمليات الشراء بكميات متعدّدة ويمنح الأذونات استنادًا إلى أذونات الاستخدام على كمية الشراء المحددة
لتنفيذ عمليات الشراء متعددة الكميات، يجب التحقّق من منطق توفير المتطلبات في تطبيقك
لكمية السلع يمكنك الوصول إلى حقل quantity
من أحد
واجهات برمجة التطبيقات التالية:
getQuantity()
من Google Play Billing Library.Purchases.products.quantity
من Google Play Developer API
بعد إضافة الإجراءات المنطقية للتعامل مع عمليات الشراء بكميات متعددة، عليك تفعيل ميزة "تعدُّد الكميات" للمنتج المناسب في التطبيق صفحة إدارة المنتجات في Google Play Console.
إرسال طلب بحث إلى إعدادات الفوترة للمستخدم
يوفّر getBillingConfigAsync()
البلد الذي يستخدمه المستخدم.
Google Play.
يمكنك الاستعلام عن إعدادات الفوترة للمستخدم بعد
جارٍ إنشاء BillingClient
. يصف مقتطف الرمز التالي
كيفية إجراء مكالمة مع الرقم getBillingConfigAsync()
. التعامل مع الرد من خلال
تنفيذ BillingConfigResponseListener
. يتلقى هذا المستمع
تعديلات على جميع طلبات البحث الخاصة بإعدادات الفوترة التي بدأت من تطبيقك.
إذا لم تتضمّن قيمة BillingResult
المعروضة أي أخطاء، يمكنك بعد ذلك التحقّق من
الحقل countryCode
في العنصر BillingConfig
للحصول على حساب المستخدم على Play
البلد.
Kotlin
// Use the default GetBillingConfigParams.
val getBillingConfigParams = GetBillingConfigParams.newBuilder().build()
billingClient.getBillingConfigAsync(getBillingConfigParams,
object : BillingConfigResponseListener {
override fun onBillingConfigResponse(
billingResult: BillingResult,
billingConfig: BillingConfig?
) {
if (billingResult.responseCode == BillingResponseCode.OK
&& billingConfig != null) {
val countryCode = billingConfig.countryCode
...
} else {
// TODO: Handle errors
}
}
})
Java
// Use the default GetBillingConfigParams.
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build();
billingClient.getBillingConfigAsync(getBillingConfigParams,
new BillingConfigResponseListener() {
public void onBillingConfigResponse(
BillingResult billingResult, BillingConfig billingConfig) {
if (billingResult.getResponseCode() == BillingResponseCode.OK
&& billingConfig != null) {
String countryCode = billingConfig.getCountryCode();
...
} else {
// TODO: Handle errors
}
}
});