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

जब 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) }
        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
}

ऐसे बिलिंग नतीजे जिन्हें फिर से इस्तेमाल किया जा सकता है

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

समस्या

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

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

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

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

समस्या

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

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

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

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

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

समस्या

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

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

इस गड़बड़ी से बचने के लिए, हमेशा BillingClient.isReady() पर कॉल करके Play Billing Library से कॉल करने से पहले, 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 Billing सेवाओं के बीच नेटवर्क कनेक्शन की समस्या हो.

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

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

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 के कैश मेमोरी को ट्रिगर करती है, ताकि वह 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 लाइब्रेरी पर कॉल करने से पहले, 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 के अलग-अलग कॉल का सही तरीके से इस्तेमाल किया हो. गड़बड़ी के बारे में ज़्यादा जानकारी के लिए, डीबग मैसेज भी देखें.