BillingResult প্রতিক্রিয়া কোডগুলি পরিচালনা করুন

যখন একটি প্লে বিলিং লাইব্রেরি কল একটি অ্যাকশন ট্রিগার করে, তখন লাইব্রেরি ফলাফল ডেভেলপারদের জানাতে একটি BillingResult প্রতিক্রিয়া প্রদান করে। উদাহরণস্বরূপ, যদি আপনি ব্যবহারকারীর জন্য উপলব্ধ অফারগুলি পেতে queryProductDetailsAsync ব্যবহার করেন, প্রতিক্রিয়া কোডে হয় একটি ঠিক আছে কোড থাকে এবং সঠিক ProductDetails অবজেক্ট প্রদান করে, অথবা এটিতে একটি ভিন্ন প্রতিক্রিয়া থাকে যা ProductDetails অবজেক্টটি প্রদান না করার কারণ নির্দেশ করে .

সব প্রতিক্রিয়া কোড ত্রুটি নয়. BillingResponseCode রেফারেন্স পৃষ্ঠা এই নির্দেশিকায় আলোচিত প্রতিটি প্রতিক্রিয়ার বিশদ বিবরণ প্রদান করে। প্রতিক্রিয়া কোডের কিছু উদাহরণ যা ত্রুটি নির্দেশ করে না:

  • BillingClient.BillingResponseCode.OK : কল দ্বারা ট্রিগার করা ক্রিয়া সফলভাবে সম্পন্ন হয়েছে৷
  • BillingClient.BillingResponseCode.USER_CANCELED : ব্যবহারকারীর কাছে প্লে স্টোর UI প্রবাহ প্রদর্শন করে এমন ক্রিয়াগুলির জন্য, এই প্রতিক্রিয়াটি নির্দেশ করে যে ব্যবহারকারী প্রক্রিয়াটি সম্পূর্ণ না করেই সেই UI ফ্লো থেকে দূরে সরে গেছে৷

যখন প্রতিক্রিয়া কোড একটি ত্রুটি নির্দেশ করে, কারণটি কখনও কখনও ক্ষণস্থায়ী অবস্থার কারণে হয়, এবং এইভাবে পুনরুদ্ধার সম্ভব। যখন একটি প্লে বিলিং লাইব্রেরি পদ্ধতিতে একটি কল একটি 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)
  }
  ...
}

সূচকীয় ব্যাকঅফ পুনরায় চেষ্টা করুন

আমরা প্লে বিলিং লাইব্রেরি ক্রিয়াকলাপগুলির জন্য সূচকীয় ব্যাকঅফ ব্যবহার করার পরামর্শ দিই যা ব্যাকগ্রাউন্ডে ঘটে এবং ব্যবহারকারী সেশনে থাকাকালীন ব্যবহারকারীর অভিজ্ঞতাকে প্রভাবিত করে না।

উদাহরণস্বরূপ, নতুন কেনাকাটা স্বীকার করার সময় এটি বাস্তবায়ন করা উপযুক্ত হবে কারণ এই অপারেশনটি ব্যাকগ্রাউন্ডে ঘটতে পারে, এবং কোনো ত্রুটি ঘটলে স্বীকৃতি বাস্তব সময়ে ঘটতে হবে না।

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)

সমস্যা

এই ত্রুটিটি নির্দেশ করে যে ডিভাইস এবং প্লে সিস্টেমগুলির মধ্যে নেটওয়ার্ক সংযোগে একটি সমস্যা ছিল৷

সম্ভাব্য রেজোলিউশন

পুনরুদ্ধার করতে, সাধারণ পুনঃপ্রচার বা সূচকীয় ব্যাকঅফ ব্যবহার করুন, কোন ক্রিয়া ত্রুটিটি ট্রিগার করেছে তার উপর নির্ভর করে।

SERVICE_TIMEOUT (ত্রুটি কোড -3)

সমস্যা

এই ত্রুটিটি নির্দেশ করে যে Google Play প্রতিক্রিয়া জানাতে সক্ষম হওয়ার আগে অনুরোধটি সর্বাধিক টাইমআউটে পৌঁছেছে। এটি হতে পারে, উদাহরণস্বরূপ, প্লে বিলিং লাইব্রেরি কল দ্বারা অনুরোধ করা ক্রিয়া সম্পাদনে বিলম্বের কারণে।

সম্ভাব্য রেজোলিউশন

এটি সাধারণত একটি ক্ষণস্থায়ী সমস্যা। একটি সহজ বা সূচকীয় ব্যাকঅফ কৌশল ব্যবহার করে অনুরোধটি পুনরায় চেষ্টা করুন, কোন ক্রিয়াটি ত্রুটি ফিরিয়ে দিয়েছে তার উপর নির্ভর করে।

নীচের SERVICE_DISCONNECTED এর বিপরীতে, Google Play বিলিং পরিষেবার সাথে সংযোগ বিচ্ছিন্ন করা হয়নি, এবং আপনাকে শুধুমাত্র প্লে বিলিং লাইব্রেরি অপারেশনের চেষ্টা করা যাই হোক না কেন পুনরায় চেষ্টা করতে হবে৷

SERVICE_DISCONNECTED (ত্রুটি কোড -1)

সমস্যা

এই মারাত্মক ত্রুটিটি নির্দেশ করে যে BillingClient এর মাধ্যমে Google Play Store পরিষেবার সাথে ক্লায়েন্ট অ্যাপের সংযোগ বিচ্ছিন্ন করা হয়েছে৷

সম্ভাব্য রেজোলিউশন

যতটা সম্ভব এই ত্রুটিটি এড়াতে, সর্বদা BillingClient.isReady() এ কল করে প্লে বিলিং লাইব্রেরির সাথে কল করার আগে Google Play পরিষেবাগুলির সংযোগ পরীক্ষা করুন৷

SERVICE_DISCONNECTED থেকে পুনরুদ্ধারের চেষ্টা করার জন্য, আপনার ক্লায়েন্ট অ্যাপটি BillingClient.startConnection ব্যবহার করে সংযোগটি পুনরায় স্থাপন করার চেষ্টা করবে।

ঠিক SERVICE_TIMEOUT এর মতই, কোন ক্রিয়া ত্রুটিটি ট্রিগার করেছে তার উপর নির্ভর করে, সাধারণ পুনঃপ্রচার বা সূচকীয় ব্যাকঅফ ব্যবহার করুন৷

SERVICE_UNAVAILABLE (ত্রুটি কোড 2)

গুরুত্বপূর্ণ তথ্য:

Google Play বিলিং লাইব্রেরি 6.0.0 থেকে শুরু করে, নেটওয়ার্ক সমস্যার জন্য SERVICE_UNAVAILABLE আর ফেরত দেওয়া হয় না৷ এটি ফেরত দেওয়া হয় যখন বিলিং পরিষেবা অনুপলব্ধ থাকে এবং SERVICE_TIMEOUT কেস পরিস্থিতিতে অবনমিত হয়৷

সমস্যা

এই ক্ষণস্থায়ী ত্রুটিটি নির্দেশ করে যে Google Play বিলিং পরিষেবা বর্তমানে অনুপলব্ধ৷ বেশিরভাগ ক্ষেত্রে, এর মানে হল ক্লায়েন্ট ডিভাইস এবং Google Play বিলিং পরিষেবাগুলির মধ্যে যে কোনও জায়গায় নেটওয়ার্ক সংযোগের সমস্যা রয়েছে৷

সম্ভাব্য রেজোলিউশন

এটি সাধারণত একটি ক্ষণস্থায়ী সমস্যা। একটি সহজ বা সূচকীয় ব্যাকঅফ কৌশল ব্যবহার করে অনুরোধটি পুনরায় চেষ্টা করুন, কোন ক্রিয়াটি ত্রুটি ফিরিয়ে দিয়েছে তার উপর নির্ভর করে।

SERVICE_DISCONNECTED এর বিপরীতে, Google Play বিলিং পরিষেবার সাথে সংযোগ বিচ্ছিন্ন করা হয়নি, এবং যে কোনো অপারেশন করার চেষ্টা করা হচ্ছে তা আপনাকে আবার চেষ্টা করতে হবে।

BILLING_UNavaILABLE (ত্রুটি কোড 3)

সমস্যা

এই ত্রুটিটি নির্দেশ করে যে ক্রয় প্রক্রিয়া চলাকালীন একটি ব্যবহারকারীর বিলিং ত্রুটি ঘটেছে৷ কখন এটি ঘটতে পারে তার উদাহরণগুলির মধ্যে রয়েছে:

  • ব্যবহারকারীর ডিভাইসে প্লে স্টোর অ্যাপটি পুরানো।
  • ব্যবহারকারী একটি অসমর্থিত দেশে আছে.
  • ব্যবহারকারী একজন এন্টারপ্রাইজ ব্যবহারকারী, এবং তাদের এন্টারপ্রাইজ অ্যাডমিন ব্যবহারকারীদের কেনাকাটা করতে অক্ষম করেছে।
  • Google Play ব্যবহারকারীর অর্থপ্রদানের পদ্ধতি চার্জ করতে অক্ষম৷ উদাহরণস্বরূপ, ব্যবহারকারীর ক্রেডিট কার্ডের মেয়াদ শেষ হয়ে গেছে।

সম্ভাব্য রেজোলিউশন

স্বয়ংক্রিয় পুনরায় চেষ্টা এই ক্ষেত্রে সাহায্য করার সম্ভাবনা কম। যাইহোক, একটি ম্যানুয়াল পুনঃপ্রচেষ্টা সাহায্য করতে পারে যদি ব্যবহারকারী সমস্যাটি সৃষ্টিকারী অবস্থার সমাধান করে। উদাহরণস্বরূপ, যদি ব্যবহারকারী তাদের প্লে স্টোর সংস্করণকে একটি সমর্থিত সংস্করণে আপডেট করে, তাহলে প্রাথমিক অপারেশনের একটি ম্যানুয়াল পুনরায় চেষ্টা কাজ করতে পারে।

ব্যবহারকারী সেশনে না থাকার সময় এই ত্রুটিটি ঘটলে, আবার চেষ্টা করার অর্থ নাও হতে পারে। যখন আপনি ক্রয় প্রবাহের ফলে একটি BILLING_UNAVAILABLE ত্রুটি পান, তখন খুব সম্ভবত ব্যবহারকারী ক্রয় প্রক্রিয়া চলাকালীন Google Play থেকে প্রতিক্রিয়া পেয়েছেন এবং কী ভুল হয়েছে সে সম্পর্কে সচেতন হতে পারেন৷ এই ক্ষেত্রে, আপনি কিছু ভুল হয়েছে তা উল্লেখ করে একটি ত্রুটি বার্তা দেখাতে পারেন এবং ব্যবহারকারীকে সমস্যাটি সমাধান করার পরে একটি ম্যানুয়াল পুনরায় চেষ্টা করার বিকল্প দিতে "আবার চেষ্টা করুন" বোতাম অফার করতে পারেন।

ত্রুটি (ত্রুটি কোড 6)

সমস্যা

এটি একটি মারাত্মক ত্রুটি যা Google Play এর সাথে একটি অভ্যন্তরীণ সমস্যা নির্দেশ করে৷

সম্ভাব্য রেজোলিউশন

কখনও কখনও অভ্যন্তরীণ Google Play সমস্যা যা ERROR দিকে পরিচালিত করে তা ক্ষণস্থায়ী হয় এবং প্রশমনের জন্য সূচকীয় ব্যাকঅফ সহ একটি পুনঃচেষ্টা প্রয়োগ করা যেতে পারে। ব্যবহারকারীরা যখন সেশনে থাকে, তখন একটি সাধারণ পুনঃপ্রচেষ্টা বাঞ্ছনীয়।

ITEM_ALREADY_OWNED

সমস্যা

এই প্রতিক্রিয়াটি ইঙ্গিত করে যে Google Play ব্যবহারকারী ইতিমধ্যেই সাবস্ক্রিপশন বা এককালীন ক্রয় পণ্যের মালিক তারা কেনার চেষ্টা করছেন৷ বেশিরভাগ ক্ষেত্রে, এটি একটি ক্ষণস্থায়ী ত্রুটি নয়, যখন এটি একটি পুরানো Google Play এর ক্যাশে দ্বারা সৃষ্ট হয়।

সম্ভাব্য রেজোলিউশন

কারণটি একটি ক্যাশে সমস্যা না হলে এই ত্রুটিটি ঘটতে এড়াতে, ব্যবহারকারীর ইতিমধ্যেই এটির মালিক থাকা অবস্থায় ক্রয়ের জন্য কোনও পণ্য অফার করবেন না৷ আপনি যখন ক্রয়ের জন্য উপলব্ধ পণ্যগুলি দেখান তখন ব্যবহারকারীর এনটাইটেলমেন্টগুলি পরীক্ষা করে দেখে নিন এবং ব্যবহারকারী সেই অনুযায়ী কী ক্রয় করতে পারে তা ফিল্টার করুন৷ যখন ক্লায়েন্ট অ্যাপটি একটি ক্যাশে সমস্যার কারণে এই ত্রুটিটি পায়, তখন ত্রুটিটি Google Play এর ক্যাশেকে প্লে-এর ব্যাকএন্ড থেকে সাম্প্রতিক ডেটার সাথে আপডেট করতে ট্রিগার করে। ত্রুটির পরে পুনরায় চেষ্টা করা এই ক্ষেত্রে এই নির্দিষ্ট ক্ষণস্থায়ী উদাহরণটি সমাধান করা উচিত। একটি ITEM_ALREADY_OWNED পাওয়ার পরে BillingClient.queryPurchasesAsync() এ কল করুন ব্যবহারকারী পণ্যটি অধিগ্রহণ করেছেন কিনা তা পরীক্ষা করতে এবং যদি এটি না হয় তবে ক্রয়ের পুনরায় চেষ্টা করার জন্য একটি সাধারণ পুনঃচেষ্টা যুক্তি প্রয়োগ করুন৷

ITEM_NOT_OWNED

সমস্যা

এই ক্রয় প্রতিক্রিয়াটি নির্দেশ করে যে Google Play ব্যবহারকারী সাবস্ক্রিপশন বা এককালীন ক্রয় পণ্যটির মালিক নয় যা ব্যবহারকারী প্রতিস্থাপন, স্বীকার বা ব্যবহার করার চেষ্টা করছেন। বেশিরভাগ ক্ষেত্রে এটি একটি ক্ষণস্থায়ী ত্রুটি নয় যখন এটি Google Play-এর ক্যাশে পুরানো অবস্থায় চলে যাওয়ার কারণে ঘটে।

সম্ভাব্য রেজোলিউশন

যখন একটি ক্যাশে সমস্যার কারণে ত্রুটিটি প্রাপ্ত হয়, তখন ত্রুটিটি Google Play এর ক্যাশেকে প্লে-এর ব্যাকএন্ড থেকে সর্বশেষ ডেটা আপডেট করার জন্য ট্রিগার করে। ত্রুটির পরে একটি সাধারণ পুনরায় চেষ্টা করার কৌশল দিয়ে পুনরায় চেষ্টা করা এই নির্দিষ্ট ক্ষণস্থায়ী উদাহরণটি সমাধান করা উচিত। একটি ITEM_NOT_OWNED পাওয়ার পরে BillingClient.queryPurchasesAsync() কে কল করুন যাতে ব্যবহারকারী পণ্যটি অর্জন করেছেন কিনা তা পরীক্ষা করতে৷ যদি তারা না থাকে, ক্রয় পুনরায় চেষ্টা করার জন্য সহজ পুনঃপ্রচেষ্টা যুক্তি ব্যবহার করুন.

অ-পুনরুদ্ধারযোগ্য বিলিং ফলাফল প্রতিক্রিয়া

আপনি পুনরায় চেষ্টা যুক্তি ব্যবহার করে এই ত্রুটিগুলি থেকে পুনরুদ্ধার করতে পারবেন না৷

FEATURE_NOT_SUPPORTED

সমস্যা

এই অ-পুনরুদ্ধারযোগ্য ত্রুটিটি নির্দেশ করে যে Google Play বিলিং বৈশিষ্ট্যটি ব্যবহারকারীর ডিভাইসে সমর্থিত নয়, সম্ভবত একটি পুরানো Play Store সংস্করণের কারণে।

উদাহরণস্বরূপ, সম্ভবত আপনার ব্যবহারকারীদের কিছু ডিভাইস ইন-অ্যাপ মেসেজিং সমর্থন করে না।

সম্ভাব্য প্রশমন

প্লে বিলিং লাইব্রেরিতে কল করার আগে বৈশিষ্ট্য সমর্থন পরীক্ষা করতে BillingClient.isFeatureSupported() ব্যবহার করুন৷

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

USER_CANCELED

সমস্যা

ব্যবহারকারী বিলিং ফ্লো UI থেকে ক্লিক করেছেন।

সম্ভাব্য রেজোলিউশন

এটি শুধুমাত্র তথ্যপূর্ণ এবং করুণভাবে ব্যর্থ হতে পারে।

ITEM_UNavailable

সমস্যা

এই ব্যবহারকারীর জন্য Google Play বিলিং সদস্যতা বা এককালীন ক্রয় পণ্যটি কেনার জন্য উপলব্ধ নয়৷

সম্ভাব্য প্রশমন

নিশ্চিত করুন যে আপনার অ্যাপটি প্রস্তাবিত হিসাবে queryProductDetailsAsync এর মাধ্যমে পণ্যের বিবরণ রিফ্রেশ করে। প্রয়োজনে অতিরিক্ত রিফ্রেশ প্রয়োগ করতে Play Console কনফিগারেশনে আপনার পণ্যের ক্যাটালগ কত ঘন ঘন পরিবর্তিত হয় তা বিবেচনা করুন। শুধুমাত্র Google Play বিলিং-এ এমন পণ্য বিক্রি করার চেষ্টা করুন যা queryProductDetailsAsync এর মাধ্যমে সঠিক তথ্য প্রদান করে। কোনো অসঙ্গতির জন্য পণ্যের যোগ্যতা কনফিগারেশন পরীক্ষা করুন। উদাহরণ স্বরূপ, আপনি হয়ত এমন একটি পণ্যের জন্য অনুসন্ধান করছেন যা শুধুমাত্র একটি অঞ্চলের জন্য উপলব্ধ যা ব্যবহারকারী কেনার চেষ্টা করছেন। ক্রয়ের জন্য উপলব্ধ হতে, একটি পণ্য সক্রিয় হতে হবে, এর অ্যাপ প্রকাশ করতে হবে এবং এর অ্যাপটি ব্যবহারকারীর দেশে উপলব্ধ হতে হবে।

কখনও কখনও, বিশেষ করে পরীক্ষার সময়, পণ্য কনফিগারেশনে সবকিছু সঠিক, তবে ব্যবহারকারীরা এখনও এই ত্রুটিটি দেখতে পান। এটি Google-এর সার্ভার জুড়ে পণ্যের বিবরণ প্রচারে বিলম্বের কারণে হতে পারে। পরে আবার চেষ্টা করুন.

DEVELOPER_ERROR

সমস্যা

এটি একটি মারাত্মক ত্রুটি যা নির্দেশ করে যে আপনি ভুলভাবে একটি API ব্যবহার করছেন৷ উদাহরণস্বরূপ, BillingClient.launchBillingFlow এ ভুল প্যারামিটার সরবরাহ করলে এই ত্রুটি হতে পারে।

সম্ভাব্য রেজোলিউশন

নিশ্চিত করুন যে আপনি বিভিন্ন প্লে বিলিং লাইব্রেরি কলগুলি সঠিকভাবে ব্যবহার করছেন৷ এছাড়াও, ত্রুটি সম্পর্কে আরও তথ্যের জন্য ডিবাগ বার্তাটি পরীক্ষা করুন৷