يوضّح هذا المستند كيفية دمج Google Play Billing Library في تطبيقك لبدء بيع المنتجات.
مراحل عملية الشراء
في ما يلي مسار شراء نموذجي لعملية شراء لمرة واحدة أو اشتراك.
- اعرض للمستخدم ما يمكنه شراؤه.
- ابدأ مسار الشراء ليقبل المستخدم عملية الشراء.
- تأكيد عملية الشراء على الخادم
- قدِّم المحتوى للمستخدم.
- تأكيد تسليم المحتوى بالنسبة إلى المنتجات الاستهلاكية، استهلك عملية الشراء ليتمكّن المستخدم من شراء المنتج مرة أخرى.
يتم تجديد الاشتراكات تلقائيًا إلى أن يتم إلغاؤها. يمكن أن يمر الاشتراك بالحالات التالية:
- نشط: المستخدم في وضع جيد ويمكنه الوصول إلى الاشتراك.
- تم الإلغاء: ألغى المستخدم الاشتراك ولكن لا يزال بإمكانه الوصول إلى المزايا حتى انتهاء صلاحيته.
- في فترة السماح: واجه المستخدم مشكلة في الدفع، ولكن لا يزال بإمكانه الوصول إلى المحتوى بينما تعيد Google محاولة تحصيل الدفعة من خلال طريقة الدفع.
- معلَّق: واجه المستخدم مشكلة في الدفع ولم يعُد بإمكانه الوصول إلى المحتوى بينما تعيد Google محاولة الدفع باستخدام طريقة الدفع.
- متوقّف مؤقتًا: أوقف المستخدم إذن وصوله مؤقتًا ولن يتمكّن من الوصول إلى أن يستأنف الإذن.
- منتهية الصلاحية: ألغى المستخدم الاشتراك وفقد إمكانية الوصول إليه. ويُعدّ المستخدم غير نشط عند انتهاء صلاحية الاشتراك.
بدء عملية ربط بخدمة Google Play
الخطوة الأولى لدمج تطبيقك مع نظام الفوترة في Google Play هي إضافة مكتبة Google Play Billing Library إلى تطبيقك وبدء الاتصال.
إضافة اعتمادية Google Play Billing Library
أضِف تبعية Google Play Billing Library إلى ملف build.gradle في تطبيقك كما هو موضّح:
أنيق
dependencies { def billing_version = "9.1.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "9.1.0" implementation("com.android.billingclient:billing:$billing_version") }
إذا كنت تستخدم لغة Kotlin، فإنّ وحدة KTX في Google Play Billing Library تحتوي على إضافات Kotlin ودعم لبرامج الكوروتين التي تتيح لك كتابة لغة Kotlin الاصطلاحية عند استخدام Google Play Billing Library. لتضمين هذه الإضافات في مشروعك، أضِف التبعية التالية إلى ملف build.gradle في تطبيقك كما هو موضّح:
أنيق
dependencies { def billing_version = "9.1.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "9.1.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
إعداد BillingClient
بعد إضافة عنصر تابع لملف مكتبة Google Play Billing Library، عليك
إعداد مثيل BillingClient. BillingClient هي الواجهة الرئيسية
للاتصال بين Google Play Billing Library
وبقية تطبيقك. توفّر BillingClient طرقًا مريحة، سواء كانت متزامنة
أو غير متزامنة، للعديد من عمليات الفوترة الشائعة. يُرجى ملاحظة ما يلي:
- ننصحك بفتح اتصال واحد نشط في
BillingClientفي المرة الواحدة لتجنُّب عمليات معاودة الاتصال المتعددة فيPurchasesUpdatedListenerلحدث واحد. - ننصحك ببدء عملية ربط لـ BillingClient عند تشغيل تطبيقك أو عند ظهوره في المقدّمة لضمان معالجة تطبيقك لعمليات الشراء في الوقت المناسب. يمكن تحقيق ذلك باستخدام
ActivityLifecycleCallbacksالمسجَّل من قِبلregisterActivityLifecycleCallbacksوالاستماع إلى onActivityResumed لبدء الاتصال عند رصد استئناف نشاط لأول مرة. يُرجى الرجوع إلى قسم معالجة عمليات الشراء لمزيد من التفاصيل حول سبب اتّباع أفضل الممارسات هذه. تذكَّر أيضًا إنهاء الاتصال عند إغلاق تطبيقك.
لإنشاء 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() { // If automatic service reconnection is enabled, this can be left empty (no-op) // because the library handles retries. You can still use this for non-retry // tasks like logging or updating the UI to reflect a disconnected state. // Otherwise, 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. // It's a good practice to query products after the connection is established. queryProductDetails(); } } @Override public void onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. // This is automatically handled by the library when you call a method that requires a connection. } });
إعادة إنشاء اتصال تلقائيًا
مع طرح طريقة enableAutoServiceReconnection() في
BillingClient.Builder في الإصدار 8.0.0، يمكن لمكتبة Play Billing Library
الآن إعادة إنشاء اتصال الخدمة تلقائيًا في حال إجراء طلب بيانات من واجهة برمجة التطبيقات
أثناء قطع الاتصال بالخدمة. يمكن أن يؤدي ذلك إلى تقليل عدد الردود SERVICE_DISCONNECTED لأنّه تتم معالجة إعادة الاتصال داخليًا قبل طلب بيانات من واجهة برمجة التطبيقات.
كيفية تفعيل إعادة الاتصال التلقائي
عند إنشاء مثيل BillingClient، استخدِم الإجراء
enableAutoServiceReconnection() في BillingClient.Builder
لتفعيل إعادة الاتصال التلقائي.
Kotlin
val billingClient = BillingClient.newBuilder(context) .setListener(listener) .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()) .enableAutoServiceReconnection() // Add this line to enable reconnection .build()
Java
BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build();
عرض المنتجات المتاحة للشراء
بعد إنشاء اتصال بخدمة Google Play، ستكون جاهزًا لطلب البحث عن منتجاتك المتاحة وعرضها للمستخدمين.
يُعدّ طلب تفاصيل المنتجات خطوة مهمة قبل عرض منتجاتك للمستخدمين، لأنّها تعرض معلومات المنتجات بلغتهم. بالنسبة إلى الاشتراكات، يُرجى التأكّد من أنّ عرض منتجك يتوافق مع جميع سياسات Google Play.
للاستعلام عن تفاصيل المنتجات المدفوعة لمرة واحدة، يمكنك استدعاء الطريقة queryProductDetailsAsync. يمكن أن تعرض هذه الطريقة عروضًا متعدّدة استنادًا إلى إعدادات المنتج المدفوع لمرة واحدة. لمزيد من المعلومات، يُرجى الاطّلاع على خيارات وعروض شراء متعدّدة للمنتجات المدفوعة لمرة واحدة.
للتعامل مع نتيجة العملية غير المتزامنة، يجب أيضًا تحديد
مستمع ينفّذ واجهة ProductDetailsResponseListener.
يمكنك بعد ذلك إلغاء onProductDetailsResponse، الذي يرسل إشعارًا إلى المستمع عند انتهاء طلب البحث، كما هو موضّح في المثال التالي:
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( listOf( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build() ) ) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, queryProductDetailsResult -> if (billingResult.responseCode == BillingResponseCode.OK) { for (productDetails in queryProductDetailsResult.productDetailsList) { // Process successfully retrieved product details here. } for (unfetchedProduct in queryProductDetailsResult.unfetchedProductList) { // Handle any unfetched products as appropriate. } } }
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,
QueryProductDetailsResult queryProductDetailsResult) {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
for (ProductDetails productDetails : queryProductDetailsResult.getProductDetailsList()) {
// Process successfully retrieved product details here.
}
for (UnfetchedProduct unfetchedProduct : queryProductDetailsResult.getUnfetchedProductList()) {
// Handle any unfetched products as appropriate.
}
}
}
}
)
عند الاستعلام عن تفاصيل المنتج، يجب تمرير مثيل من
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. لتقديم الدعم المناسب لهذا السيناريو، تعرَّف على كيفية استخدام ميزات التوافق مع الأنظمة القديمة في دليل نقل البيانات إلى الإصدار 7 من Play Billing Library.
معالجة النتيجة
تخزِّن Google Play Billing Library نتائج طلب البحث في عنصر
QueryProductDetailsResult. يحتوي QueryProductDetailsResult على List من عناصر ProductDetails. يمكنك بعد ذلك استدعاء مجموعة متنوعة من الطرق على كل عنصر ProductDetails في القائمة لعرض المعلومات ذات الصلة حول منتج مدفوع لمرة واحدة تم جلبه بنجاح، مثل سعره أو وصفه. للاطّلاع على تفاصيل المنتج المتاحة، يُرجى مراجعة قائمة الطرق في فئة ProductDetails.
يحتوي QueryProductDetailsResult أيضًا على List من عناصر
UnfetchedProduct. يمكنك بعد ذلك طلب كل UnfetchedProduct
للحصول على رمز حالة يتوافق مع سبب تعذُّر الجلب.
للاطّلاع على معلومات المنتجات غير المسترجَعة المتوفّرة، راجِع قائمة الطرق في فئة UnfetchedProduct.
قبل عرض منتج للبيع، تأكَّد من أنّ المستخدم لا يملك المنتج بالفعل. إذا كان لدى المستخدم منتج استهلاكي لا يزال في مكتبة العناصر، يجب أن يستهلك العنصر قبل أن يتمكّن من شرائه مرة أخرى.
قبل تقديم اشتراك، تأكَّد من أنّ المستخدم غير مشترك حاليًا. يُرجى أيضًا مراعاة ما يلي:
بالنسبة إلى الاشتراكات، تعرض طريقة
queryProductDetailsAsync()تفاصيل المنتجات المتوفّرة عند الاشتراك و50 عرضًا ترويجيًا كحدّ أقصى مؤهَّل للمستخدم لكل اشتراك. إذا حاول المستخدم شراء عرض غير مؤهَّل (على سبيل المثال، إذا كان التطبيق يعرض قائمة قديمة بالعروض المؤهَّلة)، سيُعلم Google Play المستخدم بأنّه غير مؤهَّل، ويمكن للمستخدم اختيار شراء الخطة الأساسية بدلاً من ذلك.بالنسبة إلى المنتجات المدفوعة لمرة واحدة، لا تعرض طريقة
queryProductDetailsAsync()سوى العروض المؤهَّلة للمستخدم. إذا حاول المستخدم شراء عرض غير مؤهَّل له (على سبيل المثال، إذا وصل المستخدم إلى الحد الأقصى لعدد عمليات الشراء)، سيُبلغه Google 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) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.getSubscriptionOfferDetails() // 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<BillingFlowParams.ProductDetailsParams> productDetailsParamsList = ImmutableList.of( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.getSubscriptionOfferDetails() // 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()، يعرض النظام شاشة الشراء على Google Play. يعرض الشكل 1 شاشة شراء اشتراك:
تتصل Google Play بـ onPurchasesUpdated() لتقديم نتيجة عملية الشراء إلى مستمع ينفّذ واجهة PurchasesUpdatedListener. يتم تحديد أداة الاستماع باستخدام طريقة setListener() عند تهيئة العميل.
يجب تنفيذ onPurchasesUpdated() للتعامل مع رموز الاستجابة المحتملة. يوضّح المثال التالي كيفية إلغاء onPurchasesUpdated():
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling 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) {
// Process the purchase as described in the next section.
}
} else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user canceling the purchase flow.
} else {
// Handle any other error codes.
}
}
تؤدي عملية الشراء الناجحة إلى ظهور شاشة نجاح عملية الشراء على Google Play مشابهة للشكل 2.
تؤدي عملية الشراء الناجحة أيضًا إلى إنشاء رمز مميّز للشراء، وهو معرّف فريد يمثّل المستخدم ومعرّف المنتج للمنتج المدفوع لمرة واحدة الذي تم شراؤه. يمكن لتطبيقاتك تخزين الرمز المميّز للشراء محليًا، ولكننا ننصح بشدة بتمرير الرمز المميّز إلى خادم الخلفية الآمن حيث يمكنك التحقّق من عملية الشراء والحماية من الاحتيال. يتم شرح هذه العملية بمزيد من التفصيل في مقالة رصد عمليات الشراء ومعالجتها.
يتم أيضًا إرسال إيصال بالمعاملة إلى المستخدم عبر البريد الإلكتروني، ويتضمّن الإيصال رقم تعريف الطلب أو معرّفًا فريدًا للمعاملة. يتلقّى المستخدمون رسالة إلكترونية تتضمّن مُعرّف طلب فريدًا لكل عملية شراء لمنتج مدفوع لمرة واحدة، وكذلك لعملية شراء الاشتراك الأوّلي وعمليات التجديد التلقائي المتكرّرة اللاحقة. يمكنك استخدام معرّف الطلب لإدارة عمليات ردّ الأموال في Google Play Console.
تحديد سعر مخصّص
إذا كان من الممكن توزيع تطبيقك على المستخدمين في الاتحاد الأوروبي، استخدِم طريقة
setIsOfferPersonalized() عند طلب launchBillingFlow للإفصاح
للمستخدمين عن أنّه تم تخصيص سعر المنتج باستخدام عملية اتخاذ القرار المبرمَجة.
يجب الرجوع إلى المادة. 6 (1) (ea) CRD من "توجيه حقوق المستهلك" 2011/83/EU لمعرفة ما إذا كان السعر الذي يُعرض للمستخدمين مُخصّصًا أو لا.
تتطلّب السمة setIsOfferPersonalized() قيمة منطقية. عندما يكون true، تتضمّن واجهة مستخدم Google Play
الإفصاح. عندما تكون قيمة السمة false، تحذف واجهة المستخدم الإفصاح. القيمة التلقائية هي false.
لمزيد من المعلومات، يُرجى الانتقال إلى مركز مساعدة المستهلكين.
إرفاق معرّفات المستخدمين
عند بدء مسار الشراء، يمكن لتطبيقك إرفاق أي معرّفات مستخدمين لديك للمستخدم الذي يجري عملية الشراء باستخدام obfuscatedAccountId أو obfuscatedProfileId. يمكن أن يكون المعرّف على سبيل المثال نسخة مخفية من معلومات تسجيل دخول المستخدم في نظامك. يمكن أن يساعد ضبط هذه المَعلمات Google في رصد عمليات الاحتيال. بالإضافة إلى ذلك، يمكن أن تساعدك في التأكّد من أنّ عمليات الشراء منسوبة إلى المستخدم المناسب كما هو موضّح في منح الأذونات للمستخدمين.
رصد عمليات الشراء ومعالجتها
ينطبق رصد عملية الشراء ومعالجتها الموضّح في هذا القسم على جميع أنواع عمليات الشراء، بما في ذلك عمليات الشراء خارج التطبيق، مثل عمليات تحصيل قيمة العروض الترويجية.
يرصد تطبيقك عمليات الشراء الجديدة وعمليات الشراء المُعلّقة المكتملة بإحدى الطرق التالية:
- عند استدعاء
onPurchasesUpdatedنتيجة استدعاء تطبيقك لـlaunchBillingFlow(كما هو موضّح في القسم السابق) أو إذا كان تطبيقك يعمل باتصال نشط مع Billing Library عند إجراء عملية شراء خارج تطبيقك أو عند اكتمال عملية شراء مُعلّقة. على سبيل المثال، يوافق أحد أفراد العائلة على عملية شراء معلّقة على جهاز آخر. - عندما يستدعي تطبيقك واجهة برمجة التطبيقات queryPurchasesAsync للاستعلام عن عمليات الشراء التي أجراها المستخدم
بالنسبة إلى الحالة رقم 1، سيتم استدعاء onPurchasesUpdated تلقائيًا لعمليات الشراء الجديدة أو المكتملة طالما أنّ تطبيقك قيد التشغيل ولديه اتصال نشط بمكتبة Google Play Billing. إذا لم يكن تطبيقك قيد التشغيل أو لم يكن لديه
اتصال نشط بمكتبة الفوترة في Google Play، لن يتم استدعاء onPurchasesUpdated. يُرجى العِلم أنّه يُنصح بأن يحاول تطبيقك الحفاظ على اتصال نشط طالما كان تطبيقك في المقدّمة، وذلك لكي يتلقّى تطبيقك إشعارات في الوقت المناسب بشأن عمليات الشراء.
بالنسبة إلى الخطوة رقم 2، يجب طلب البيانات من خلال BillingClient.queryPurchasesAsync() للتأكّد من أنّ تطبيقك يعالج جميع عمليات الشراء. ننصحك بإجراء ذلك عندما ينشئ تطبيقك اتصالاً بنجاح مع Google Play Billing Library (وهو ما يُنصح به عند تشغيل تطبيقك أو ظهوره في المقدّمة كما هو موضّح في إعداد BillingClient). ويمكن تحقيق ذلك من خلال استدعاء queryPurchasesAsync عند تلقّي نتيجة ناجحة من onServiceConnected. من المهم اتّباع هذه التوصية للتعامل مع الأحداث والحالات التالية:
- مشاكل في الشبكة أثناء عملية الشراء: يمكن للمستخدم إجراء عملية شراء ناجحة وتلقّي تأكيد من Google، ولكن قد ينقطع اتصال جهازه بالشبكة قبل أن يتلقّى الجهاز والتطبيق إشعارًا بعملية الشراء من خلال
PurchasesUpdatedListener. - أجهزة متعددة: قد يشتري المستخدم منتجًا على جهاز واحد ثم يتوقع رؤية المنتج عند تبديل الأجهزة.
- التعامل مع عمليات الشراء التي تتم خارج تطبيقك: يمكن إجراء بعض عمليات الشراء، مثل الاستفادة من العروض الترويجية، خارج تطبيقك.
- التعامل مع عمليات الانتقال بين حالات الشراء: قد يُكمل المستخدم عملية الدفع مقابل عملية شراء مُعلّقة أثناء عدم تشغيل تطبيقك، ويتوقّع تلقّي تأكيد على إكمال عملية الشراء عند فتح تطبيقك.
- الاشتراكات المعلَّقة: قد يتم تعليق الاشتراك خلال دورة حياة الاشتراك. ستعرض واجهة برمجة التطبيقات BillingClient.queryPurchasesAsync() الاشتراكات المعلّقة فقط في حال ضبط المَعلمة
includeSuspendedSubscriptionsعلىQueryPurchasesParams.Builder. لا يتم عرض الاشتراكات المعلّقة فيPurchasesUpdatedListener.
بعد أن يرصد تطبيقك عملية شراء جديدة أو مكتملة، يجب أن ينفّذ ما يلي:
- أكِّد عملية الشراء.
- منح المحتوى للمستخدم مقابل عمليات الشراء المكتملة
- إرسال إشعار إلى المستخدم
- إعلام Google بأنّ تطبيقك قد عالج عمليات الشراء المكتملة
تتم مناقشة هذه الخطوات بالتفصيل في الأقسام التالية متبوعة بقسم لتلخيص جميع الخطوات.
تأكيد عملية الشراء
يجب أن يتحقّق تطبيقك دائمًا من شرعية عمليات الشراء قبل منح المزايا للمستخدم. ويمكن إجراء ذلك باتّباع الإرشادات الموضّحة في مقالة إثبات ملكية عمليات الشراء قبل منح الأذونات. بعد التحقّق من عملية الشراء فقط، يجب أن يواصل تطبيقك معالجة عملية الشراء ومنح المستخدم الحقوق، كما هو موضّح في القسم التالي. إذا تعذّر إتمام عملية شراء بسبب عدم اجتيازها عمليات التحقّق من الأهلية أو إساءة الاستخدام، يُرجى الاطّلاع على التعامل مع عمليات الشراء المرفوضة أو التي لم يتم إكمالها.
منح المستخدم إذن الوصول إلى المحتوى
بعد أن يتحقّق تطبيقك من عملية شراء، يمكنه مواصلة منح الإذن للمستخدم وإرسال إشعار إليه. قبل منح الإذن، تأكَّد من أنّ تطبيقك يتحقّق من أنّ حالة الشراء هي PURCHASED. إذا كانت عملية الشراء في حالة "في انتظار المراجعة"، يجب أن يُعلم تطبيقك المستخدم بأنّه لا يزال بحاجة إلى إكمال الإجراءات لإتمام عملية الشراء قبل منحه الإذن.
لا تمنح الإذن إلا عندما تنتقل حالة عملية الشراء من "في انتظار المراجعة" إلى "تمت عملية الشراء".
يمكنك الاطّلاع على معلومات إضافية في مقالة التعامل مع المعاملات في انتظار المعالجة.
إذا أرفقت معرّفات المستخدمين بعملية الشراء كما هو موضّح في قسم إرفاق معرّفات المستخدمين، يمكنك استردادها واستخدامها لتحديد المستخدم الصحيح في نظامك. يكون هذا الأسلوب مفيدًا عند تسوية عمليات الشراء التي فقد تطبيقك سياقها بشأن المستخدم الذي تم إجراء عملية الشراء من أجله. للحماية من إساءة الاستخدام، ينصح Google Play بالتحقّق من هذه المعرّفات في الخلفية الآمنة قبل منح الأذونات. لمزيد من المعلومات، اطّلِع على مقالة التأكّد من عمليات الشراء قبل منح الأذونات. يُرجى العِلم أنّ عمليات الشراء التي تتم خارج تطبيقك لن يتم ضبط هذه المعرّفات لها. في هذه الحالة، يمكن لتطبيقك إما منح الإذن للمستخدم الذي سجّل الدخول أو مطالبة المستخدم باختيار حساب مفضّل.
بالنسبة إلى الطلبات المُسبَقة، تكون عملية الشراء في حالة "في انتظار المراجعة" قبل الوصول إلى وقت الإصدار. ستكتمل عملية شراء الطلب المُسبَق في وقت الإصدار وستتغيّر الحالة إلى "تم الشراء" بدون اتّخاذ أي إجراءات إضافية.
إشعار المستخدم
بعد منح الإذن للمستخدم، من المفترض أن يعرض تطبيقك إشعارًا للإقرار بنجاح عملية الشراء. بفضل الإشعار، لن يشعر المستخدم بالارتباك بشأن ما إذا كانت عملية الشراء قد اكتملت بنجاح، ما قد يؤدي إلى توقّف المستخدم عن استخدام تطبيقك أو التواصل مع فريق دعم المستخدمين أو تقديم شكوى بشأن ذلك على وسائل التواصل الاجتماعي. يُرجى العِلم أنّ تطبيقك قد يرصد التعديلات على عمليات الشراء في أي وقت خلال دورة حياة التطبيق. على سبيل المثال، يوافق أحد الوالدَين على عملية شراء معلّقة على جهاز آخر، وفي هذه الحالة قد يرغب تطبيقك في تأخير إرسال إشعار إلى المستخدم إلى وقت مناسب. في ما يلي بعض الأمثلة على الحالات التي يكون فيها التأخير مناسبًا:
- أثناء جزء الإجراء من لعبة أو مشاهد سينمائية، قد يؤدي عرض رسالة إلى تشتيت انتباه المستخدم. في هذه الحالة، عليك إرسال إشعار إلى المستخدم بعد انتهاء جزء الإجراء.
- أثناء البرنامج التعليمي الأوّلي وأجزاء إعداد المستخدم في اللعبة على سبيل المثال، قد يكون أحد المستخدمين قد أجرى عملية شراء خارج تطبيقك قبل تثبيته. ننصحك بإعلام المستخدمين الجدد بالمكافأة فور فتحهم اللعبة أو أثناء الإعداد الأولي للمستخدم. إذا كان تطبيقك يتطلّب من المستخدم إنشاء حساب أو تسجيل الدخول قبل منحه الإذن، ننصحك بإبلاغ المستخدم بالخطوات التي يجب إكمالها للمطالبة بعملية الشراء. وهذا أمر بالغ الأهمية لأنّه يتم ردّ الأموال المدفوعة مقابل عمليات الشراء بعد 3 أيام إذا لم يعالج تطبيقك عملية الشراء.
عند إشعار المستخدم بعملية شراء، ينصح Google Play باستخدام الآليات التالية:
- عرض مربّع حوار داخل التطبيق
- تسليم الرسالة إلى صندوق الرسائل داخل التطبيق، مع توضيح أنّه تتوفّر رسالة جديدة في صندوق الرسائل داخل التطبيق
- استخدِم رسالة إشعار من نظام التشغيل.
يجب أن يُعلم الإشعار المستخدم بالمزايا التي حصل عليها. على سبيل المثال، "لقد اشتريت 100 عملة ذهبية". بالإضافة إلى ذلك، إذا كانت عملية الشراء نتيجةً لميزة في برنامج مثل Play Pass، سيُعلم تطبيقك المستخدم بذلك. على سبيل المثال، "تلقّيت العناصر" لقد حصلت للتو على 100 جوهرة من خلال Play Pass. متابعة". قد يتضمّن كل برنامج إرشادات حول النص المقترَح عرضه للمستخدمين لإعلامهم بالمزايا.
إعلام Google بأنّه تمت معالجة عملية الشراء
بعد أن يمنح تطبيقك الإذن للمستخدم ويُبلغه بنجاح المعاملة، يجب أن يُبلغ تطبيقك Google بأنّه تمت معالجة عملية الشراء بنجاح. ويتم ذلك من خلال الإقرار بعملية الشراء، ويجب إجراؤه خلال ثلاثة أيام حتى لا يتم ردّ الأموال تلقائيًا وإلغاء حق الاستخدام. يتم توضيح عملية تأكيد الأنواع المختلفة من عمليات الشراء في الأقسام التالية.
المنتجات الاستهلاكية
بالنسبة إلى المنتجات الاستهلاكية، إذا كان تطبيقك يتضمّن خادمًا خلفيًا آمنًا، ننصحك باستخدام
Purchases.products:consume لاستهلاك عمليات الشراء بشكل موثوق. تأكَّد من أنّ عملية الشراء لم يتم استهلاكها من قبل من خلال التحقّق من consumptionState من نتيجة طلب Purchases.products:get. إذا كان تطبيقك مخصّصًا للعملاء فقط
بدون واجهة خلفية، استخدِم consumeAsync() من
Google Play Billing Library. تستوفي كلتا الطريقتين متطلبات الإقرار وتشيران إلى أنّ تطبيقك قد منح المستخدم الإذن بالوصول إلى المحتوى.
تتيح هذه الطرق أيضًا لتطبيقك إتاحة المنتج المدفوع لمرة واحدة المتوافق مع رمز الشراء المميّز المُدخل لإعادة الشراء. باستخدام consumeAsync()، عليك أيضًا تمرير كائن ينفّذ واجهة ConsumeResponseListener. يعالج هذا العنصر نتيجة عملية الاستهلاك. يمكنك
إلغاء طريقة onConsumeResponse() التي تستدعيها
Google Play Billing Library عند اكتمال العملية.
يوضّح المثال التالي استهلاك منتج باستخدام Google Play Billing Library من خلال رمز الشراء المميّز المرتبط به:
Kotlin
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
Java
ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build(); ConsumeResponseListener listener = (billingResult, 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 Billing Library:
Kotlin
val client: BillingClient = billingClient val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
Java
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { if (!purchase.isAcknowledged()) { AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); billingClient.acknowledgePurchase(acknowledgePurchaseParams, (billingResult) -> { // Acknowledgment handled. }); } }
الاشتراكات
تتم إدارة الاشتراكات بشكل مشابه للمنتجات غير الاستهلاكية. إذا أمكن، استخدِم
Purchases.subscriptions.acknowledge من
Google Play Developer API للإقرار بعملية الشراء بشكل موثوق من
الخلفية الآمنة. تأكَّد من أنّه لم يسبق الإقرار بعملية الشراء من خلال
التحقّق من acknowledgementState في مورد الشراء من
Purchases.subscriptions:get. في الحالات الأخرى، يمكنك إقرار استلام اشتراك باستخدام BillingClient.acknowledgePurchase() من Google Play Billing Library بعد التحقّق من isAcknowledged(). يجب تأكيد جميع عمليات الشراء الأولية للاشتراكات. لا حاجة إلى إقرار تجديدات الاشتراك. لمزيد من المعلومات حول الحالات التي يجب فيها تأكيد الاشتراكات، يمكنك الاطّلاع على موضوع بيع الاشتراكات.
التعامل مع عمليات الشراء المرفوضة أو غير المكتملة
إذا تعذّر التحقّق من عملية الشراء في الخلفية أو من التحقّق من أهلية المستخدم أو من عمليات الاحتيال وإساءة الاستخدام، أو إذا لم يتمكّن نظامك من تنفيذ الإذن، لا تمنح الإذن ولا تُعلِم بالاستلام أو تستهلك عملية الشراء.
على الرغم من أنّ عمليات الشراء غير المُقَرّ بها يتم ردّ أموالها وإلغاؤها تلقائيًا بعد انتهاء صلاحية نافذة الإقرار كشبكة أمان للمستهلك، لا تعتمد على نافذة انتهاء الصلاحية هذه لرفض عمليات الشراء. يؤدي انتهاء صلاحية نافذة الإقرار إلى ترك الطلب في حالة عدم الإقرار، وهو أمر غامض بالنسبة إلى Google Play، الذي لا يمكنه التمييز بين رفض المطوّر المتعمّد ومهلة معالجة الخلفية.
بدلاً من ذلك، عليك إلغاء عمليات الشراء المرفوضة وردّ أموالها على الفور من الخلفية باستخدام Google Play Developer API:
- الاشتراكات: اتّصِل على
purchases.subscriptionsv2.revokeباستخدام"fullRefund": {}فيrevocationContext. سيؤدي ذلك إلى إنهاء الاشتراك على الفور وإلغاء إمكانية الوصول إلى المحتوى وبدء عملية استرداد الأموال بالكامل. - المنتجات المدفوعة لمرة واحدة: يمكنك استدعاء
orders.refundمع ضبط المَعلمةrevokeعلىtrueلردّ أموال الطلب على الفور وإبطال حق الوصول إليه. عند استدعاء هذه الطريقة، يجب تمرير معرّف طلب الشراء الذي يمكن استرداده من خلالPurchase.getOrderId()أوpurchases.productsv2.getproductpurchasev2. لا تستدعِ مطلقًاconsumeAsync()أوacknowledgePurchase()أوPurchases.products:consumeأوPurchases.products:acknowledgeفي عمليات الشراء المرفوضة. - سلوك ”الإشعارات في الوقت الفعلي الخاصة بالمطوّرين“ و”عمليات الشراء المُلغاة“: تؤدي عمليات الإبطال وردّ الأموال التي يبدأها المطوّر (
purchases.subscriptionsv2.revokeوorders.refundمع ضبطrevokeعلىtrue) إلى تفعيل ”الإشعارات في الوقت الفعلي الخاصة بالمطوّرين“ ويتم تسجيلها في Voided Purchases API (purchases.voidedpurchases.listمع ضبط حقل الاستجابةvoidedSourceعلى1للمطوّر):- الاشتراكات: يتم إرسال إشعار
SUBSCRIPTION_REVOKEDوVoidedPurchaseNotification. - المنتجات المدفوعة لمرة واحدة: يتم إرسال إشعار
VoidedPurchaseNotification(وإشعارONE_TIME_PRODUCT_CANCELEDإذا تم ضبط تطبيقك في Play Console لتلقّي جميع إشعارات المنتجات المدفوعة لمرة واحدة). - يؤدي استدعاء
orders.refundبدون ضبطrevokeعلىtrueإلى ردّ أموال الطلب بدون إبطال الإذن ولا يؤدي إلى إرسال إشعار بإبطال عملية الشراء أو إلغائها. لمزيد من التفاصيل، يُرجى الاطّلاع على مقالة إدارة الاشتراكات وعمليات الشراء لمرة واحدة.
- الاشتراكات: يتم إرسال إشعار
ملخّص
في ما يلي ملخّص لهذه الخطوات.
أرسِل عملية الشراء إلى الخلفية الآمنة للتحقّق من عمليات الشراء قبل منح الأذونات.
عدِّل مساحة تخزين الأذونات من خلال عملية الشراء. إذا كانت حالة عملية الشراء هي PENDING، تأكَّد من وضع علامة "في انتظار المراجعة" على الأهلية وعدم حصول المستخدم على المزايا بعد. يُنصح بتنفيذ هذه الخطوة على الخلفية الآمنة، ويمكن دمجها في طلب بيانات من واجهة برمجة التطبيقات إلى الخلفية في الخطوة 1.
أرسِل إشعارًا إلى المستخدم باستخدام الرسائل المناسبة (مع تأخير الإشعار إذا لزم الأمر كما تمت مناقشته سابقًا).
أبلِغ Google بأنّه تمت معالجة عملية الشراء باتّباع الخطوات الموضّحة في قسم معالجة عمليات الشراء.
للتأكّد من أنّ تطبيقك قد نفّذ هذه الخطوات بشكل صحيح، يمكنك اتّباع دليل الاختبار.
التعامل مع المعاملات في انتظار المراجعة
يتيح Google Play المعاملات في انتظار المعالجة، أو المعاملات التي تتطلّب خطوة واحدة أو أكثر بين الوقت الذي يبدأ فيه المستخدم عملية شراء والوقت الذي تتم فيه معالجة طريقة الدفع الخاصة بعملية الشراء. يجب ألا يمنح تطبيقك حق الوصول إلى هذه الأنواع من عمليات الشراء إلى أن تبلّغك Google بأنّه تم تحصيل الرسوم من طريقة الدفع الخاصة بالمستخدم بنجاح.
على سبيل المثال، يمكن للمستخدم بدء معاملة من خلال اختيار متجر حقيقي سيدفع فيه لاحقًا نقدًا. يتلقّى المستخدم رمزًا من خلال كل من الإشعار والبريد الإلكتروني. عندما يصل المستخدم إلى المتجر، يمكنه استخدام الرمز مع الصرّاف والدفع نقدًا. بعد ذلك، تُرسل Google إشعارًا إليك وإلى المستخدم يفيد باستلام الدفعة. ويمكن لتطبيقك بعد ذلك منح المستخدم الإذن بالوصول إلى المحتوى.
يمكنك استدعاء enablePendingPurchases() كجزء من عملية إعداد
BillingClient لتفعيل المعاملات في انتظار المعالجة في تطبيقك. يجب أن يفعّل تطبيقك
المعاملات في انتظار المعالجة ويتيحها للمنتجات المدفوعة لمرة واحدة. قبل إضافة
الدعم، تأكَّد من فهم دورة حياة الشراء للمعاملات
في انتظار المراجعة.
عندما يتلقّى تطبيقك عملية شراء جديدة، سواء من خلال
PurchasesUpdatedListener أو نتيجة طلب
queryPurchasesAsync، استخدِم طريقة getPurchaseState() لتحديد ما إذا كانت حالة الشراء هي PURCHASED أو PENDING. يجب منح الإذن فقط عندما تكون الحالة PURCHASED.
إذا كان تطبيقك قيد التشغيل وكان لديك اتصال نشط بواجهة برمجة التطبيقات Play Billing Library
عندما يُكمل المستخدم عملية الشراء، سيتم استدعاء PurchasesUpdatedListener مرة أخرى، وستصبح قيمة PurchaseState هي PURCHASED. في هذه المرحلة، يمكن لتطبيقك معالجة عملية الشراء باستخدام الطريقة العادية لرصد عمليات الشراء ومعالجتها. يجب أن يستدعي تطبيقك أيضًا queryPurchasesAsync() في طريقة onResume() الخاصة بتطبيقك للتعامل مع عمليات الشراء التي انتقلت إلى الحالة PURCHASED أثناء عدم تشغيل تطبيقك.
عندما تنتقل عملية الشراء من الحالة PENDING إلى الحالة PURCHASED، يتلقّى عميل
real_time_developer_notifications إشعارًا من النوع
ONE_TIME_PRODUCT_PURCHASED أو SUBSCRIPTION_PURCHASED. في حال إلغاء عملية الشراء، ستتلقّى إشعارًا من ONE_TIME_PRODUCT_CANCELED أو SUBSCRIPTION_PENDING_PURCHASE_CANCELED. يمكن أن يحدث ذلك إذا لم يكمل العميل عملية الدفع في الإطار الزمني المطلوب. يُرجى العِلم أنّه يمكنك دائمًا استخدام Google Play Developer API للتحقّق من الحالة الحالية لعملية شراء.
التعامل مع عمليات الشراء بكميات متعددة
يتيح Google Play للعملاء شراء أكثر من منتج واحد من النوع نفسه في معاملة واحدة من خلال تحديد كمية من سلة التسوّق، وذلك في الإصدار 4.0 والإصدارات الأحدث من Google Play Billing Library. ومن المتوقّع أن يتعامل تطبيقك مع عمليات الشراء المتعدّدة الكمية ويمنح الإذن بالوصول إلى المحتوى استنادًا إلى كمية الشراء المحدّدة.
لإتاحة عمليات الشراء المتعدّدة، يجب أن يتحقّق منطق توفير الميزات في تطبيقك من كمية السلع. يمكنك الوصول إلى حقل 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 للحصول على بلد المستخدم على Google 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 { // Handle errors } } } )
Java
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build(); billingClient.getBillingConfigAsync( getBillingConfigParams, (billingResult, billingConfig) -> { if (billingResult.getResponseCode() == BillingResponseCode.OK && billingConfig != null) { String countryCode = billingConfig.getCountryCode(); } else { // TODO: Handle errors } });