बिलिंग नतीजे के रिस्पॉन्स कोड मैनेज करना

जब Play Billing Library का कोई कॉल किसी कार्रवाई को ट्रिगर करता है, तो लाइब्रेरी डेवलपर को नतीजे की जानकारी देने के लिए, BillingResult का जवाब देती है. उदाहरण के लिए, अगर उपयोगकर्ता के लिए उपलब्ध ऑफ़र पाने के लिए, queryProductDetailsAsync का इस्तेमाल किया जाता है, तो रिस्पॉन्स कोड में OK कोड और सही ProductDetails ऑब्जेक्ट होता है. इसके अलावा, इसमें कोई दूसरा रिस्पॉन्स भी हो सकता है, जिसमें यह बताया गया हो कि ProductDetails ऑब्जेक्ट क्यों नहीं दिया जा सका.

सभी रिस्पॉन्स कोड गड़बड़ी के नहीं होते. BillingResponseCode रेफ़रंस पेज पर, इस गाइड में बताए गए हर जवाब के बारे में पूरी जानकारी दी गई है. गड़बड़ियों के बारे में बताने वाले रिस्पॉन्स कोड के कुछ उदाहरण यहां दिए गए हैं:

  • BillingClient.BillingResponseCode.OK : कॉल से ट्रिगर की गई कार्रवाई पूरी हो गई.
  • BillingClient.BillingResponseCode.USER_CANCELED : उपयोगकर्ता को Play Store के यूज़र इंटरफ़ेस (यूआई) फ़्लो दिखाने वाली कार्रवाइयों के लिए, यह रिस्पॉन्स बताता है कि उपयोगकर्ता ने प्रोसेस पूरी किए बिना, उन यूआई फ़्लो से बाहर निकला है.

जब रिस्पॉन्स कोड में गड़बड़ी का पता चलता है, तो कभी-कभी इसकी वजह कुछ समय के लिए बनी परिस्थितियां होती हैं. इसलिए, इसे ठीक किया जा सकता है. जब Play Billing Library के किसी तरीके को कॉल करने पर, BillingResponseCode वैल्यू मिलती है, तो आपको कॉल फिर से करना चाहिए. इससे, आपको उस स्थिति को ठीक करने में मदद मिलेगी. अन्य मामलों में, शर्तों को ट्रांज़िशन के तौर पर नहीं माना जाता. इसलिए, दोबारा कोशिश करने का सुझाव नहीं दिया जाता.

कुछ समय के लिए होने वाली गड़बड़ियों को ठीक करने के लिए, फिर से कोशिश करने की अलग-अलग रणनीतियां अपनाई जा सकती हैं. ये रणनीतियां इन बातों पर निर्भर करती हैं कि क्या गड़बड़ी, उपयोगकर्ता के सेशन के दौरान होती है. उदाहरण के लिए, जब कोई उपयोगकर्ता खरीदारी के फ़्लो से गुज़र रहा हो या गड़बड़ी बैकग्राउंड में होती है. उदाहरण के लिए, जब onResume के दौरान, उपयोगकर्ता की मौजूदा खरीदारी के बारे में क्वेरी की जा रही हो. नीचे दिए गए फिर से कोशिश करने की रणनीतियों वाले सेक्शन में, इन अलग-अलग रणनीतियों के उदाहरण दिए गए हैं. साथ ही, फिर से कोशिश किए जा सकने वाले BillingResult जवाबों के सेक्शन में, यह सुझाव दिया गया है कि हर जवाब कोड के लिए कौनसी रणनीति सबसे सही है.

गड़बड़ी के कुछ जवाबों में, रिस्पॉन्स कोड के अलावा, डिबग करने और लॉग करने के लिए मैसेज भी शामिल होते हैं.

रणनीतियों को फिर से आज़माना

आसानी से दोबारा कोशिश करना

जब उपयोगकर्ता सेशन में हो, तो फिर से कोशिश करने की आसान रणनीति लागू करना बेहतर होता है. इससे गड़बड़ी की वजह से, उपयोगकर्ता अनुभव में कम से कम रुकावट आएगी. ऐसे में, हमारा सुझाव है कि आप रीट्राइ करने की एक आसान रणनीति अपनाएं. इसमें, ज़्यादा से ज़्यादा कोशिशों को, बाहर निकलने की शर्त के तौर पर शामिल करें.

नीचे दिए गए उदाहरण में, BillingClient से कनेक्ट करते समय होने वाली गड़बड़ी को ठीक करने के लिए, फिर से कोशिश करने की एक आसान रणनीति के बारे में बताया गया है:

class BillingClientWrapper(context: Context) : PurchasesUpdatedListener {
  // Initialize the BillingClient.
  private val billingClient = BillingClient.newBuilder(context)
    .setListener(this)
    .enablePendingPurchases()
    .build()

  // Establish a connection to Google Play.
  fun startBillingConnection() {
    billingClient.startConnection(object : BillingClientStateListener {
      override fun onBillingSetupFinished(billingResult: BillingResult) {
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
          Log.d(TAG, "Billing response OK")
          // The BillingClient is ready. You can now query Products Purchases.
        } else {
          Log.e(TAG, billingResult.debugMessage)
          retryBillingServiceConnection()
        }
      }

      override fun onBillingServiceDisconnected() {
        Log.e(TAG, "GBPL Service disconnected")
        retryBillingServiceConnection()
      }
    })
  }

  // Billing connection retry logic. This is a simple max retry pattern
  private fun retryBillingServiceConnection() {
    val maxTries = 3
    var tries = 1
    var isConnectionEstablished = false
    do {
      try {
        billingClient.startConnection(object : BillingClientStateListener {
          override fun onBillingSetupFinished(billingResult: BillingResult) {
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
              isConnectionEstablished = true
              Log.d(TAG, "Billing connection retry succeeded.")
            } else {
              Log.e(
                TAG,
                "Billing connection retry failed: ${billingResult.debugMessage}"
              )
            }
          }
        })
      } catch (e: Exception) {
        e.message?.let { Log.e(TAG, it) }
      } finally {
        tries++
      }
    } while (tries <= maxTries && !isConnectionEstablished)
  }
  ...
}

एक्सपोनेंशियल बैकऑफ़ की मदद से फिर से कोशिश करना

हमारा सुझाव है कि Play Billing Library के उन ऑपरेशन के लिए एक्सपोनेंशियल बैकऑफ़ का इस्तेमाल करें जो बैकग्राउंड में होते हैं और उपयोगकर्ता के सेशन के दौरान, उपयोगकर्ता अनुभव पर असर नहीं डालते.

उदाहरण के लिए, नई खरीदारी की पुष्टि करते समय, इसे लागू करना सही होगा. ऐसा इसलिए, क्योंकि यह कार्रवाई बैकग्राउंड में हो सकती है और गड़बड़ी होने पर, पुष्टि को रीयल टाइम में करने की ज़रूरत नहीं होती.

private fun acknowledge(purchaseToken: String): BillingResult {
  val params = AcknowledgePurchaseParams.newBuilder()
    .setPurchaseToken(purchaseToken)
    .build()
  var ackResult = BillingResult()
  billingClient.acknowledgePurchase(params) { billingResult ->
    ackResult = billingResult
  }
  return ackResult
}

suspend fun acknowledgePurchase(purchaseToken: String) {

  val retryDelayMs = 2000L
  val retryFactor = 2
  val maxTries = 3

  withContext(Dispatchers.IO) {
    acknowledge(purchaseToken)
  }

  AcknowledgePurchaseResponseListener { acknowledgePurchaseResult ->
    val playBillingResponseCode =
    PlayBillingResponseCode(acknowledgePurchaseResult.responseCode)
    when (playBillingResponseCode) {
      BillingClient.BillingResponseCode.OK -> {
        Log.i(TAG, "Acknowledgement was successful")
      }
      BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> {
        // This is possibly related to a stale Play cache.
        // Querying purchases again.
        Log.d(TAG, "Acknowledgement failed with ITEM_NOT_OWNED")
        billingClient.queryPurchasesAsync(
          QueryPurchasesParams.newBuilder()
            .setProductType(BillingClient.ProductType.SUBS)
            .build()
        )
        { billingResult, purchaseList ->
          when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
              purchaseList.forEach { purchase ->
                acknowledge(purchase.purchaseToken)
              }
            }
          }
        }
      }
      in setOf(
         BillingClient.BillingResponseCode.ERROR,
         BillingClient.BillingResponseCode.SERVICE_DISCONNECTED,
         BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE,
       ) -> {
        Log.d(
          TAG,
          "Acknowledgement failed, but can be retried --
          Response Code: ${acknowledgePurchaseResult.responseCode} --
          Debug Message: ${acknowledgePurchaseResult.debugMessage}"
        )
        runBlocking {
          exponentialRetry(
            maxTries = maxTries,
            initialDelay = retryDelayMs,
            retryFactor = retryFactor
          ) { acknowledge(purchaseToken) }
        }
      }
      in setOf(
         BillingClient.BillingResponseCode.BILLING_UNAVAILABLE,
         BillingClient.BillingResponseCode.DEVELOPER_ERROR,
         BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED,
       ) -> {
        Log.e(
          TAG,
          "Acknowledgement failed and cannot be retried --
          Response Code: ${acknowledgePurchaseResult.responseCode} --
          Debug Message: ${acknowledgePurchaseResult.debugMessage}"
        )
        throw Exception("Failed to acknowledge the purchase!")
      }
    }
  }
}

private suspend fun <T> exponentialRetry(
  maxTries: Int = Int.MAX_VALUE,
  initialDelay: Long = Long.MAX_VALUE,
  retryFactor: Int = Int.MAX_VALUE,
  block: suspend () -> T
): T? {
  var currentDelay = initialDelay
  var retryAttempt = 1
  do {
    runCatching {
      delay(currentDelay)
      block()
    }
      .onSuccess {
        Log.d(TAG, "Retry succeeded")
        return@onSuccess;
      }
      .onFailure { throwable ->
        Log.e(
          TAG,
          "Retry Failed -- Cause: ${throwable.cause} -- Message: ${throwable.message}"
        )
      }
    currentDelay *= retryFactor
    retryAttempt++
  } while (retryAttempt < maxTries)

  return block() // last attempt
}

BillingResult के ऐसे रिस्पॉन्स जिन्हें फिर से पाया जा सकता है

NETWORK_ERROR (गड़बड़ी कोड 12)

समस्या

इस गड़बड़ी से पता चलता है कि डिवाइस और Play सिस्टम के बीच इंटरनेट कनेक्शन में कोई समस्या हुई.

समस्या हल करने का तरीका

इसे ठीक करने के लिए, फिर से कोशिश करने या एक्सपोनेंशियल बैकऑफ़ का इस्तेमाल करें. यह इस बात पर निर्भर करता है कि किस कार्रवाई की वजह से गड़बड़ी हुई है.

SERVICE_TIMEOUT (गड़बड़ी कोड -3)

समस्या

इस गड़बड़ी से पता चलता है कि Google Play के जवाब देने से पहले, अनुरोध की समयसीमा खत्म हो गई है. उदाहरण के लिए, ऐसा तब हो सकता है, जब Play Billing Library कॉल के अनुरोध की गई कार्रवाई को पूरा करने में देरी हो.

समस्या हल करने का तरीका

आम तौर पर, यह समस्या कुछ समय के लिए होती है. अनुरोध को फिर से कोशिश करें. इसके लिए, सिंपल या एक्सपोनेंशियल बैकऑफ़ रणनीति का इस्तेमाल करें. यह इस बात पर निर्भर करता है कि किस ऐक्शन की वजह से गड़बड़ी हुई है.

नीचे दिए गए SERVICE_DISCONNECTED के उलट, Google Play Billing की सेवा से कनेक्शन नहीं टूटता. आपको सिर्फ़ वही Play Billing Library का काम फिर से करना होगा जिसे करने की कोशिश की गई थी.

SERVICE_DISCONNECTED (गड़बड़ी कोड -1)

समस्या

यह गंभीर गड़बड़ी बताती है कि BillingClient के ज़रिए, क्लाइंट ऐप्लिकेशन का Google Play Store सेवा से कनेक्टिविटी बंद हो गई है.

समस्या हल करने का तरीका

इस गड़बड़ी से बचने के लिए, Play Billing Library से कॉल करने से पहले, BillingClient.isReady() को कॉल करके, Google Play services से कनेक्ट होने की जांच करें.

SERVICE_DISCONNECTED से रिकवरी करने के लिए, आपके क्लाइंट ऐप्लिकेशन को BillingClient.startConnection का इस्तेमाल करके, फिर से कनेक्शन बनाने की कोशिश करनी चाहिए.

SERVICE_TIMEOUT के साथ की गई तरह ही, गड़बड़ी को ट्रिगर करने वाली कार्रवाई के आधार पर, फिर से कोशिश करने या एक्सपोनेंशियल बैकऑफ़ का इस्तेमाल करें.

SERVICE_UNAVAILABLE (गड़बड़ी कोड 2)

अहम जानकारी:

Google Play Billing Library के 6.0.0 वर्शन से, नेटवर्क से जुड़ी समस्याओं के लिए SERVICE_UNAVAILABLE को अब नहीं दिखाया जाएगा. यह तब दिखता है, जब बिलिंग सेवा उपलब्ध न हो और SERVICE_TIMEOUT के पुराने केस के उदाहरणों में.

समस्या

यह गड़बड़ी कुछ समय के लिए दिखती है. इससे पता चलता है कि फ़िलहाल, Google Play Billing की सेवा उपलब्ध नहीं है. ज़्यादातर मामलों में, इसका मतलब है कि क्लाइंट डिवाइस और Google Play की बिलिंग सेवाओं के बीच, इंटरनेट कनेक्शन में कहीं भी समस्या है.

समस्या हल करने का तरीका

आम तौर पर, यह समस्या कुछ समय के लिए होती है. अनुरोध को फिर से कोशिश करें. इसके लिए, सिंपल या एक्सपोनेंशियल बैकऑफ़ रणनीति का इस्तेमाल करें. यह इस बात पर निर्भर करता है कि किस ऐक्शन की वजह से गड़बड़ी हुई है.

SERVICE_DISCONNECTED के उलट, Google Play Billing सेवा से कनेक्शन नहीं टूटता. साथ ही, आपको जो भी कार्रवाई करनी है उसे फिर से करने की ज़रूरत होती है.

BILLING_UNAVAILABLE (गड़बड़ी कोड 3)

समस्या

इस गड़बड़ी से पता चलता है कि खरीदारी की प्रोसेस के दौरान, उपयोगकर्ता की बिलिंग से जुड़ी कोई गड़बड़ी हुई है. ऐसा तब हो सकता है, जब:

  • उपयोगकर्ता के डिवाइस पर Play Store ऐप्लिकेशन का वर्शन पुराना हो गया है.
  • उपयोगकर्ता किसी ऐसे देश में है जहां यह सुविधा उपलब्ध नहीं है.
  • उपयोगकर्ता, एंटरप्राइज़ खाते का इस्तेमाल करता है और उसके एंटरप्राइज़ एडमिन ने उपयोगकर्ताओं के लिए खरीदारी करने की सुविधा बंद कर दी है.
  • Google Play, उपयोगकर्ता के पैसे चुकाने के तरीके से शुल्क नहीं ले पा रहा है. उदाहरण के लिए, हो सकता है कि उपयोगकर्ता के क्रेडिट कार्ड की समयसीमा खत्म हो गई हो.

समस्या हल करने का तरीका

इस मामले में, अपने-आप दोबारा कोशिश करने की सुविधा काम नहीं करेगी. हालांकि, अगर उपयोगकर्ता उस समस्या को ठीक कर देता है जिसकी वजह से समस्या हुई है, तो मैन्युअल तरीके से फिर से कोशिश करने से मदद मिल सकती है. उदाहरण के लिए, अगर उपयोगकर्ता अपने Play Store के वर्शन को, इस्तेमाल किए जा सकने वाले वर्शन पर अपडेट करता है, तो शुरुआती कार्रवाई को मैन्युअल तरीके से फिर से आज़माने पर काम हो सकता है.

अगर यह गड़बड़ी तब होती है, जब उपयोगकर्ता सेशन में नहीं होता है, तो फिर से कोशिश करना शायद सही न हो. अगर आपको खरीदारी के फ़्लो की वजह से BILLING_UNAVAILABLE गड़बड़ी का मैसेज मिलता है, तो हो सकता है कि खरीदारी की प्रोसेस के दौरान उपयोगकर्ता को Google Play से सुझाव/राय मिली हो. साथ ही, हो सकता है कि वह इस बात से वाकिफ़ हो कि क्या गड़बड़ी हुई है. इस मामले में, गड़बड़ी का मैसेज दिखाकर, उपयोगकर्ता को यह बताया जा सकता है कि कुछ गड़बड़ी हुई है. साथ ही, “फिर से कोशिश करें” बटन दिखाकर, उपयोगकर्ता को समस्या ठीक करने के बाद मैन्युअल तरीके से फिर से कोशिश करने का विकल्प दिया जा सकता है.

गड़बड़ी (गड़बड़ी कोड 6)

समस्या

यह एक गंभीर गड़बड़ी है, जो Google Play में किसी अंदरूनी समस्या की जानकारी देती है.

समस्या हल करने का तरीका

कभी-कभी Google Play की अंदरूनी समस्याओं की वजह से, ERROR का मैसेज दिखता है. हालांकि, ये समस्याएं कुछ समय के लिए होती हैं. इन्हें कम करने के लिए, एक्सपोनेंशियल बैकऑफ़ के साथ फिर से कोशिश की जा सकती है. जब उपयोगकर्ता सेशन में हों, तो फिर से कोशिश करना बेहतर होता है.

ITEM_ALREADY_OWNED

समस्या

इस जवाब से पता चलता है कि Google Play के उपयोगकर्ता के पास, वह सदस्यता या एक बार खरीदे जाने वाले प्रॉडक्ट पहले से ही है जिसे वह खरीदने की कोशिश कर रहा है. ज़्यादातर मामलों में, यह गड़बड़ी कुछ समय के लिए होती है. हालांकि, अगर यह गड़बड़ी Google Play के पुराने कैश मेमोरी की वजह से होती है, तो यह कुछ समय के लिए नहीं होती.

समस्या हल करने का तरीका

अगर कैश मेमोरी से जुड़ी समस्या नहीं है, तो इस गड़बड़ी से बचने के लिए, उपयोगकर्ता के पास पहले से मौजूद प्रॉडक्ट को खरीदने के लिए न दिखाएं. खरीदारी के लिए उपलब्ध प्रॉडक्ट दिखाते समय, उपयोगकर्ता के एनटाइटलमेंट की जांच करना न भूलें. साथ ही, उपयोगकर्ता को खरीदारी के लिए उपलब्ध प्रॉडक्ट दिखाएं. जब क्लाइंट ऐप्लिकेशन को कैश मेमोरी से जुड़ी समस्या की वजह से यह गड़बड़ी दिखती है, तो यह गड़बड़ी Google Play के बैकएंड से नए डेटा के साथ अपडेट होने के लिए, Google Play के कैश मेमोरी को ट्रिगर करती है. गड़बड़ी के बाद फिर से कोशिश करने पर, इस मामले में यह खास समस्या ठीक हो जाएगी. ITEM_ALREADY_OWNED मिलने के बाद, BillingClient.queryPurchasesAsync() को कॉल करके यह देखें कि उपयोगकर्ता ने प्रॉडक्ट खरीदा है या नहीं. अगर ऐसा नहीं है, तो खरीदारी की कोशिश फिर से करने के लिए, फिर से कोशिश करने का आसान लॉजिक लागू करें.

ITEM_NOT_OWNED

समस्या

खरीदारी के इस जवाब से पता चलता है कि Google Play के उपयोगकर्ता के पास उस सदस्यता या एक बार खरीदे जाने वाले प्रॉडक्ट का मालिकाना हक नहीं है जिसे वह बदलने, स्वीकार करने या इस्तेमाल करने की कोशिश कर रहा है. ज़्यादातर मामलों में, यह गड़बड़ी कुछ समय के लिए होती है. हालांकि, ऐसा तब नहीं होता, जब Google Play का कैश मेमोरी स्टोरेज पुराना हो गया हो.

समस्या हल करने का तरीका

कैश मेमोरी से जुड़ी समस्या की वजह से गड़बड़ी मिलने पर, Google Play के बैकएंड से नए डेटा के साथ अपडेट होने के लिए, Google Play का कैश मेमोरी ट्रिगर हो जाता है. गड़बड़ी के बाद, फिर से कोशिश करने की आसान रणनीति का इस्तेमाल करके, इस खास मामले को ठीक किया जा सकता है. ITEM_NOT_OWNED मिलने के बाद, BillingClient.queryPurchasesAsync() को कॉल करके देखें कि उपयोगकर्ता ने प्रॉडक्ट खरीदा है या नहीं. अगर ऐसा नहीं हुआ है, तो खरीदारी फिर से करने के लिए, फिर से कोशिश करने के लिए आसान लॉजिक का इस्तेमाल करें.

BillingResult के ऐसे रिस्पॉन्स जिन्हें फिर से नहीं पाया जा सकता

फिर से कोशिश करने के लॉजिक का इस्तेमाल करके, इन गड़बड़ियों को ठीक नहीं किया जा सकता.

FEATURE_NOT_SUPPORTED

समस्या

इस गड़बड़ी को फिर से रिट्रीव नहीं किया जा सकता. इससे पता चलता है कि उपयोगकर्ता के डिवाइस पर Google Play Billing की सुविधा काम नहीं करती. ऐसा, Play Store के पुराने वर्शन की वजह से हो सकता है.

उदाहरण के लिए, हो सकता है कि आपके कुछ उपयोगकर्ताओं के डिवाइसों पर, इन-ऐप्लिकेशन मैसेजिंग की सुविधा काम न करे.

जोखिम को कम करने के तरीके

Play Billing Library को कॉल करने से पहले, BillingClient.isFeatureSupported() का इस्तेमाल करके देखें कि सुविधा काम करती है या नहीं.

when {
  billingClient.isReady -> {
    if (billingClient.isFeatureSupported(BillingClient.FeatureType.IN_APP_MESSAGING)) {
       // use feature
    }
  }
}

USER_CANCELED

समस्या

उपयोगकर्ता ने बिलिंग फ़्लो के यूज़र इंटरफ़ेस (यूआई) से बाहर निकलने के लिए क्लिक किया है.

समस्या हल करने का तरीका

यह सिर्फ़ जानकारी देने के लिए है और यह बिना किसी रुकावट के काम कर सकता है.

ITEM_UNAVAILABLE

समस्या

इस उपयोगकर्ता के लिए, Google Play Billing की सदस्यता या एक बार खरीदे जाने वाले प्रॉडक्ट को खरीदने की सुविधा उपलब्ध नहीं है.

जोखिम को कम करने के तरीके

पक्का करें कि आपका ऐप्लिकेशन, सुझाए गए तरीके के मुताबिक queryProductDetailsAsync की मदद से प्रॉडक्ट की जानकारी रीफ़्रेश करता हो. ज़रूरत पड़ने पर ज़्यादा रीफ़्रेश लागू करने के लिए, इस बात का ध्यान रखें कि Play Console कॉन्फ़िगरेशन में आपके प्रॉडक्ट कैटलॉग में कितनी बार बदलाव होता है. Google Play Billing पर सिर्फ़ ऐसे प्रॉडक्ट बेचें जो queryProductDetailsAsync के ज़रिए सही जानकारी दिखाते हों. प्रॉडक्ट की ज़रूरी शर्तों के कॉन्फ़िगरेशन की जांच करें, ताकि कोई गड़बड़ी न हो. उदाहरण के लिए, हो सकता है कि आपने किसी ऐसे प्रॉडक्ट के लिए क्वेरी की हो जो सिर्फ़ उस क्षेत्र के लिए उपलब्ध है जहां उपयोगकर्ता उसे खरीदना चाहता है. कोई भी प्रॉडक्ट खरीदारी के लिए उपलब्ध होने पर ही खरीदा जा सकेगा. साथ ही, यह भी ज़रूरी है कि जिस ऐप्लिकेशन पर वह उपलब्ध है उसे पब्लिश कर दिया गया हो. इसके अलावा, यह ऐप्लिकेशन उपयोगकर्ता के देश में भी उपलब्ध होना चाहिए.

कभी-कभी, खास तौर पर टेस्टिंग के दौरान, प्रॉडक्ट के कॉन्फ़िगरेशन में सब कुछ सही होता है, लेकिन उपयोगकर्ताओं को अब भी यह गड़बड़ी दिखती है. ऐसा, Google के सर्वर पर प्रॉडक्ट की जानकारी को प्रोपेगेट होने में लगने वाले समय की वजह से हो सकता है. कुछ देर बाद फिर से कोशिश करें.

DEVELOPER_ERROR

समस्या

यह एक गंभीर गड़बड़ी है. इससे पता चलता है कि आपने एपीआई का गलत तरीके से इस्तेमाल किया है. उदाहरण के लिए, BillingClient.launchBillingFlow को गलत पैरामीटर देने पर, यह गड़बड़ी हो सकती है.

समस्या हल करने का तरीका

पक्का करें कि आपने Play Billing Library के अलग-अलग कॉल का सही तरीके से इस्तेमाल किया हो. गड़बड़ी के बारे में ज़्यादा जानकारी के लिए, डीबग मैसेज भी देखें.