จัดการโค้ดตอบกลับ Billingผลลัพธ์

เมื่อการเรียกใช้ Play Billing Library ทริกเกอร์การดำเนินการ ไลบรารีจะส่งการตอบกลับ BillingResult เพื่อแจ้งให้นักพัฒนาแอปทราบผลลัพธ์ เช่น หากคุณใช้ queryProductDetailsAsync เพื่อรับข้อเสนอที่พร้อมให้บริการแก่ผู้ใช้ โค้ดตอบกลับจะมีโค้ด OK และระบุออบเจ็กต์ ProductDetails ที่ถูกต้อง หรือมีการตอบกลับอื่นที่ระบุสาเหตุที่ระบบไม่สามารถระบุออบเจ็กต์ ProductDetails ได้

โค้ดตอบกลับบางรายการไม่ใช่ข้อผิดพลาด หน้าBillingResponseCode อ้างอิงจะอธิบายรายละเอียดของการตอบกลับแต่ละรายการ ที่กล่าวถึงในคู่มือนี้ ตัวอย่างรหัสการตอบกลับที่ไม่ได้บ่งบอกถึงข้อผิดพลาดมีดังนี้

  • BillingClient.BillingResponseCode.OK : การดำเนินการที่ทริกเกอร์โดยการเรียกใช้เสร็จสมบูรณ์แล้ว
  • BillingClient.BillingResponseCode.USER_CANCELED : สำหรับการดำเนินการที่แสดงโฟลว์ UI ของ Play Store แก่ผู้ใช้ การตอบกลับนี้ บ่งชี้ว่าผู้ใช้ไปยังโฟลว์ UI เหล่านั้นโดยไม่ทำกระบวนการ ให้เสร็จสมบูรณ์

เมื่อโค้ดการตอบกลับระบุข้อผิดพลาด สาเหตุอาจเกิดจาก สภาวะชั่วคราว และสามารถกู้คืนได้ เมื่อการเรียกเมธอด Play Billing Library แสดงผลค่า BillingResponseCode ที่บ่งบอกถึงเงื่อนไขที่กู้คืนได้ คุณควรลองเรียกอีกครั้ง ใน กรณีอื่นๆ ระบบจะไม่ถือว่าเงื่อนไขเป็นแบบชั่วคราว จึงไม่แนะนำให้ลองอีกครั้ง

ข้อผิดพลาดชั่วคราวต้องใช้กลยุทธ์การลองใหม่ที่แตกต่างกันโดยขึ้นอยู่กับปัจจัยต่างๆ เช่น ข้อผิดพลาดเกิดขึ้นเมื่อผู้ใช้อยู่ในเซสชันหรือไม่ เช่น เมื่อผู้ใช้ กำลังทำตามขั้นตอนการซื้อ หรือข้อผิดพลาดเกิดขึ้นในเบื้องหลัง เช่น เมื่อคุณกําลังค้นหาการซื้อที่มีอยู่ของผู้ใช้ระหว่าง onResume ส่วนกลยุทธ์การลองใหม่ด้านล่างมีตัวอย่างของกลยุทธ์ต่างๆ เหล่านี้ และส่วนBillingResultการตอบกลับที่ลองใหม่ได้ แนะนำกลยุทธ์ที่เหมาะกับโค้ดตอบกลับแต่ละรายการมากที่สุด

นอกเหนือจากโค้ดตอบกลับแล้ว การตอบกลับข้อผิดพลาดบางอย่างยังมีข้อความสำหรับการแก้ไขข้อบกพร่องและการบันทึก

กลยุทธ์การลองใหม่

ลองใหม่แบบง่าย

ในกรณีที่ผู้ใช้อยู่ในเซสชัน คุณควรใช้ กลยุทธ์การลองใหม่แบบง่ายๆ เพื่อให้ข้อผิดพลาดรบกวนประสบการณ์ของผู้ใช้น้อยที่สุด ในกรณีนี้ เราขอแนะนำให้ใช้กลยุทธ์การลองใหม่แบบง่ายๆ โดยมี จำนวนครั้งที่ลองสูงสุดเป็นเงื่อนไขการออก

ตัวอย่างต่อไปนี้แสดงกลยุทธ์การลองใหม่แบบง่ายเพื่อจัดการข้อผิดพลาด เมื่อสร้างการเชื่อมต่อ BillingClient

// Initialize the BillingClient.
private val billingClient = BillingClient.newBuilder(context)
    .setListener(this)
    .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
    .build()

private val coroutineScope = kotlinx.coroutines.CoroutineScope(
    kotlinx.coroutines.SupervisorJob() + kotlinx.coroutines.Dispatchers.Main.immediate
)

private var connectionJob: kotlinx.coroutines.Job? = null

// Establish a connection to Google Play.
fun startBillingConnection() {
    connectionJob?.cancel()
    connectionJob = coroutineScope.launch {
        connectWithRetry()
    }
}

// Suspended helper to perform a single connection attempt
private suspend fun connectBilling(): BillingResult =
    kotlinx.coroutines.suspendCancellableCoroutine { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }

            override fun onBillingServiceDisconnected() {
                Log.e(TAG, "Google Play Billing Service disconnected")
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Service disconnected during connection setup")
                            .build()
                    )
                } else {
                    startBillingConnection()
                }
            }
        })
    }

// Billing connection retry logic. This is a simple max retry pattern
private suspend fun connectWithRetry() {
    val maxTries = 3
    var tries = 1
    var isConnectionEstablished = false
    while (tries <= maxTries && !isConnectionEstablished) {
        val billingResult = connectBilling()
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
            isConnectionEstablished = true
            Log.d(TAG, "Billing response OK")
        } else {
            Log.e(TAG, "Billing connection retry failed: ${billingResult.debugMessage}")
            tries++
            if (tries <= maxTries) {
                delay(2000L) // Wait 2 seconds before retrying
            }
        }
    }
}

fun cleanUp() {
    coroutineScope.cancel()
}
// ...

การลองใหม่แบบ Exponential Backoff

เราขอแนะนำให้ใช้ Exponential Backoff สำหรับการดำเนินการ Play Billing Library ที่เกิดขึ้นในเบื้องหลังและไม่ส่งผลต่อประสบการณ์ของผู้ใช้ขณะที่ผู้ใช้อยู่ในเซสชัน

เช่น คุณควรใช้การดำเนินการนี้เมื่อรับทราบการซื้อใหม่ เนื่องจากสามารถดำเนินการในเบื้องหลังได้ และไม่จำเป็นต้องรับทราบแบบเรียลไทม์หากเกิดข้อผิดพลาด

private suspend fun acknowledge(purchaseToken: String): BillingResult =
    kotlinx.coroutines.suspendCancellableCoroutine { continuation ->
        val params = AcknowledgePurchaseParams.newBuilder()
            .setPurchaseToken(purchaseToken)
            .build()
        billingClient.acknowledgePurchase(params) { billingResult ->
            continuation.resumeWith(Result.success(billingResult))
        }
    }

private suspend fun queryPurchases(productType: String): Pair<BillingResult, List<Purchase>> =
    kotlinx.coroutines.suspendCancellableCoroutine { continuation ->
        val params = QueryPurchasesParams.newBuilder()
            .setProductType(productType)
            .build()
        billingClient.queryPurchasesAsync(params) { billingResult, purchaseList ->
            continuation.resumeWith(Result.success(Pair(billingResult, purchaseList)))
        }
    }

suspend fun acknowledgePurchase(purchaseToken: String) {
    val retryDelayMs = 2000L
    val retryFactor = 2
    val maxTries = 3

    var tries = 1
    var currentDelay = retryDelayMs
    var acknowledgePurchaseResult: BillingResult

    do {
        acknowledgePurchaseResult = acknowledge(purchaseToken)
        val playBillingResponseCode = acknowledgePurchaseResult.responseCode

        when (playBillingResponseCode) {
            BillingClient.BillingResponseCode.OK -> {
                Log.i(TAG, "Acknowledgement was successful")
                return
            }

            BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> {
                Log.d(TAG, "Acknowledgement failed with ITEM_NOT_OWNED")
                val (billingResult, purchaseList) = queryPurchases(BillingClient.ProductType.SUBS)
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    purchaseList.forEach { purchase ->
                        acknowledge(purchase.purchaseToken)
                    }
                }
                return
            }

            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}"
                )
                if (tries < maxTries) {
                    delay(currentDelay)
                    currentDelay *= retryFactor
                    tries++
                } else {
                    break
                }
            }

            else -> {
                Log.e(
                    TAG,
                    "Acknowledgement failed and cannot be retried -- " +
                        "Response Code: ${acknowledgePurchaseResult.responseCode} -- " +
                        "Debug Message: ${acknowledgePurchaseResult.debugMessage}"
                )
                throw Exception("Failed to acknowledge the purchase!")
            }
        }
    } while (tries <= maxTries)

    throw Exception("Failed to acknowledge the purchase after $maxTries attempts!")
}

การตอบกลับ BillingResult ที่ลองใหม่ได้

NETWORK_ERROR (รหัสข้อผิดพลาด 12)

ปัญหา

ข้อผิดพลาดนี้แสดงว่าเกิดปัญหาเกี่ยวกับการเชื่อมต่อเครือข่าย ระหว่างอุปกรณ์กับระบบ Play

การแก้ไขที่เป็นไปได้

หากต้องการกู้คืน ให้ใช้การลองใหม่แบบง่ายหรือ Exponential Backoff ขึ้นอยู่กับว่า การดำเนินการใดที่ทำให้เกิดข้อผิดพลาด

SERVICE_TIMEOUT (รหัสข้อผิดพลาด -3)

ปัญหา

ข้อผิดพลาดนี้บ่งชี้ว่าคำขอมีระยะหมดเวลาสูงสุดก่อนที่ Google Play จะตอบกลับได้ ซึ่งอาจเกิดจากความล่าช้า ในการดำเนินการที่เรียกใช้โดย Play Billing Library เป็นต้น

การแก้ไขที่เป็นไปได้

โดยปกติแล้วปัญหานี้จะเกิดขึ้นชั่วคราว ลองส่งคำขออีกครั้งโดยใช้กลยุทธ์ Exponential Backoff หรือกลยุทธ์แบบง่าย ขึ้นอยู่กับการดำเนินการที่ทำให้เกิดข้อผิดพลาด

การเชื่อมต่อกับบริการ Google Play Billing จะไม่ถูกตัดขาดเหมือนกับSERVICE_DISCONNECTED ด้านล่าง และคุณ เพียงแค่ต้องลองดำเนินการใดก็ตามใน Play Billing Library ที่พยายามทำอีกครั้ง

SERVICE_DISCONNECTED (รหัสข้อผิดพลาด -1)

ปัญหา

ข้อผิดพลาดร้ายแรงนี้บ่งชี้ว่าการเชื่อมต่อของแอปไคลเอ็นต์กับบริการ Google Play Store ผ่าน BillingClient ถูกตัดขาด

การแก้ไขที่เป็นไปได้

Play Billing Library เวอร์ชัน 8.0.0 ได้เปิดตัวenableAutoServiceReconnection() ฟีเจอร์ เราขอแนะนำอย่างยิ่งให้คุณเปิดใช้ฟีเจอร์นี้เมื่อสร้าง BillingClient ซึ่งจะช่วยให้ไลบรารีพยายามสร้างการเชื่อมต่อใหม่โดยอัตโนมัติเมื่อมีการเรียก API การเรียกเก็บเงินขณะที่บริการถูกตัดการเชื่อมต่อ ซึ่งจะช่วยลดการเกิดข้อผิดพลาดนี้ได้อย่างมาก

Kotlin

val billingClient = BillingClient.newBuilder(context)
    .setListener(listener)
    .enablePendingPurchases(
        PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()
    )
    .enableAutoServiceReconnection() // Enable automatic service reconnection
    .build()

Java

BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(listener)
    .enablePendingPurchases()
    .enableAutoServiceReconnection() // Enable automatic service reconnection
    .build();
หากคุณเปิดใช้การเชื่อมต่อบริการอีกครั้งโดยอัตโนมัติ

Play Billing Library จะพยายามเชื่อมต่อใหม่โดยอัตโนมัติ หากยังคงได้รับโค้ดตอบกลับ SERVICE_DISCONNECTED เมื่อทำการเรียก API แสดงว่าไลบรารีเชื่อมต่อใหม่ไม่ได้หลังจากพยายามโดยอัตโนมัติ ในกรณีนี้ คุณควรใช้ตรรกะการลองใหม่ในแอป

  • สําหรับการกระทําที่ผู้ใช้เริ่มต้น (ในเซสชัน): ใช้การลองใหม่แบบง่ายของการเรียก API ปัญหาที่เกิดขึ้นอาจเป็นปัญหาชั่วคราว
  • สำหรับคำขอในเบื้องหลัง: ใช้การลองใหม่ด้วย Exponential Backoff เพื่อ หลีกเลี่ยงการทำให้ระบบทำงานหนักเกินไปหากการตัดการเชื่อมต่อเป็นเวลานาน
หากคุณไม่ได้เปิดใช้การเชื่อมต่อบริการอีกครั้งโดยอัตโนมัติ

หากต้องการหลีกเลี่ยงข้อผิดพลาดนี้ให้ได้มากที่สุด ให้ตรวจสอบการเชื่อมต่อกับบริการ Google Play เสมอก่อนที่จะทำการเรียกใช้ด้วย Play Billing Library โดยการเรียกใช้ BillingClient.isReady()

หากต้องการพยายามกู้คืนจาก SERVICE_DISCONNECTED แอปไคลเอ็นต์ควรพยายามสร้างการเชื่อมต่อใหม่โดยใช้ BillingClient.startConnection

เช่นเดียวกับ SERVICE_TIMEOUT ให้ใช้การลองใหม่แบบง่ายหรือ Exponential Backoff ขึ้นอยู่กับการดำเนินการที่ทําให้เกิดข้อผิดพลาด

SERVICE_UNAVAILABLE (รหัสข้อผิดพลาด 2)

หมายเหตุสำคัญ:

ตั้งแต่ Google Play Billing Library 6.0.0 เป็นต้นไป ระบบจะไม่แสดง SERVICE_UNAVAILABLE อีกต่อไปเมื่อเกิดปัญหาเกี่ยวกับเครือข่าย ระบบจะแสดงผลเมื่อบริการเรียกเก็บเงิน ไม่พร้อมใช้งานและSERVICE_TIMEOUTสถานการณ์กรณีที่เลิกใช้งานแล้ว

ปัญหา

ข้อผิดพลาดชั่วคราวนี้บ่งชี้ว่าบริการ Google Play Billing ไม่พร้อมให้บริการในขณะนี้ ในกรณีส่วนใหญ่ ปัญหานี้หมายความว่ามีปัญหาการเชื่อมต่อเครือข่าย ระหว่างอุปกรณ์ไคลเอ็นต์กับบริการ Google Play Billing

การแก้ไขที่เป็นไปได้

โดยปกติแล้วปัญหานี้จะเกิดขึ้นชั่วคราว ลองส่งคำขออีกครั้งโดยใช้กลยุทธ์ Exponential Backoff หรือกลยุทธ์แบบง่าย ขึ้นอยู่กับการดำเนินการที่ทำให้เกิดข้อผิดพลาด

ซึ่งแตกต่างจาก SERVICE_DISCONNECTED ที่การเชื่อมต่อกับบริการ Google Play Billing จะถูกตัดขาด และคุณต้อง ลองดำเนินการใดก็ตามที่พยายามทำอีกครั้ง

BILLING_UNAVAILABLE (รหัสข้อผิดพลาด 3)

ปัญหา

ข้อผิดพลาดนี้บ่งชี้ว่าเกิดข้อผิดพลาดในการเรียกเก็บเงินจากผู้ใช้ในระหว่างกระบวนการซื้อ ตัวอย่างของกรณีที่อาจเกิดเหตุการณ์นี้มีดังนี้

  • แอป Play Store ในอุปกรณ์ของผู้ใช้เป็นเวอร์ชันเก่า
  • ผู้ใช้อยู่ในประเทศที่ไม่รองรับ
  • ผู้ใช้เป็นผู้ใช้ระดับองค์กร และผู้ดูแลระบบขององค์กรได้ปิดใช้ไม่ให้ผู้ใช้ ทำการซื้อ
  • Google Play เรียกเก็บเงินจากวิธีการชำระเงินของผู้ใช้ไม่ได้ เช่น บัตรเครดิตของผู้ใช้อาจหมดอายุ
  • ระบบบล็อกแอป Play Store (เช่น ในโหมดสำหรับเด็กที่ OEM ปรับแต่ง ไว้) ในกรณีนี้ BillingResult จะมีข้อความแก้ไขข้อบกพร่อง Play Store ถูกบล็อก

การแก้ไขที่เป็นไปได้

  • การลองอีกครั้งโดยอัตโนมัติไม่น่าจะช่วยได้ในกรณีนี้ อย่างไรก็ตาม การลองอีกครั้งด้วยตนเองอาจช่วยได้หากผู้ใช้แก้ไขเงื่อนไขที่ทำให้เกิดปัญหา ตัวอย่างเช่น หากผู้ใช้อัปเดต Play Store เป็นเวอร์ชันที่รองรับ การลอง ดำเนินการเริ่มต้นอีกครั้งด้วยตนเองอาจได้ผล

  • หากข้อผิดพลาดนี้เกิดขึ้นเมื่อผู้ใช้ไม่ได้อยู่ในเซสชัน การลองอีกครั้งอาจไม่ สมเหตุสมผล เมื่อคุณได้รับข้อผิดพลาด BILLING_UNAVAILABLE อันเป็นผลมาจากขั้นตอนการซื้อ มีแนวโน้มสูงที่ผู้ใช้จะได้รับ ความคิดเห็นจาก Google Play ในระหว่างกระบวนการซื้อและอาจทราบว่า เกิดข้อผิดพลาดอะไรขึ้น ในกรณีนี้ คุณอาจแสดงข้อความแสดงข้อผิดพลาดที่ระบุว่ามีบางอย่างผิดพลาด และเสนอปุ่มลองอีกครั้งเพื่อให้ผู้ใช้มีตัวเลือกในการ ลองอีกครั้งด้วยตนเองหลังจากแก้ไขปัญหาแล้ว

ข้อผิดพลาด (รหัสข้อผิดพลาด 6)

ปัญหา

นี่เป็นข้อผิดพลาดร้ายแรงที่บ่งบอกถึงปัญหาภายในของ Google Play เอง

การแก้ไขที่เป็นไปได้

บางครั้งปัญหาภายในของ Google Play ที่ทำให้เกิด ERROR อาจเกิดขึ้นชั่วคราว และอาจลองอีกครั้งโดยใช้การถอยแบบทวีคูณเพื่อ ลดปัญหา เมื่อผู้ใช้อยู่ในเซสชัน การลองอีกครั้งแบบง่ายๆ จะดีกว่า

ITEM_ALREADY_OWNED

ปัญหา

การตอบกลับนี้บ่งชี้ว่าผู้ใช้ Google Play เป็นเจ้าของผลิตภัณฑ์การสมัครใช้บริการหรือผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียวที่พยายามซื้ออยู่แล้ว ในกรณีส่วนใหญ่ ข้อผิดพลาดนี้ไม่ใช่ข้อผิดพลาดชั่วคราว ยกเว้นในกรณีที่เกิดจากแคชของ Google Play ที่ล้าสมัย

การแก้ไขที่เป็นไปได้

หากต้องการหลีกเลี่ยงข้อผิดพลาดนี้เมื่อสาเหตุไม่ใช่ปัญหาเกี่ยวกับแคช โปรดอย่าเสนอ ผลิตภัณฑ์ให้ซื้อเมื่อผู้ใช้เป็นเจ้าของผลิตภัณฑ์อยู่แล้ว โปรดตรวจสอบสิทธิ์ของผู้ใช้เมื่อแสดงผลิตภัณฑ์ที่พร้อมจำหน่าย และกรองสิ่งที่ผู้ใช้ซื้อได้ตามนั้น เมื่อแอปไคลเอ็นต์ได้รับข้อผิดพลาดนี้เนื่องจากปัญหาเกี่ยวกับแคช ข้อผิดพลาดจะทริกเกอร์แคชของ Google Play ให้อัปเดตข้อมูลล่าสุดจากแบ็กเอนด์ของ Play การลองอีกครั้งหลังจากเกิดข้อผิดพลาดควรแก้ไขอินสแตนซ์ชั่วคราวที่เฉพาะเจาะจงนี้ในกรณีนี้ได้ เรียกใช้ BillingClient.queryPurchasesAsync() หลังจากได้รับ ITEM_ALREADY_OWNED เพื่อตรวจสอบว่าผู้ใช้ซื้อผลิตภัณฑ์แล้วหรือไม่ และหากยังไม่ได้ซื้อ ให้ใช้ตรรกะการลองใหม่แบบง่ายเพื่อลองซื้ออีกครั้ง

ITEM_NOT_OWNED

ปัญหา

การตอบกลับการซื้อนี้บ่งชี้ว่าผู้ใช้ Google Play ไม่ได้เป็นเจ้าของการสมัครใช้บริการหรือผลิตภัณฑ์การซื้อครั้งเดียวที่ผู้ใช้พยายามจะแทนที่ รับทราบ หรือใช้ ในกรณีส่วนใหญ่ ข้อผิดพลาดนี้ไม่ใช่ข้อผิดพลาดชั่วคราว ยกเว้นในกรณีที่เกิดจากแคชของ Google Play ที่อยู่ในสถานะล้าสมัย

การแก้ไขที่เป็นไปได้

เมื่อได้รับข้อผิดพลาดเนื่องจากปัญหาเกี่ยวกับแคช ข้อผิดพลาดจะทริกเกอร์แคชของ Google Play ให้อัปเดตข้อมูลล่าสุดจากแบ็กเอนด์ของ Play การลองอีกครั้ง ด้วยกลยุทธ์การลองอีกครั้งอย่างง่ายหลังจากเกิดข้อผิดพลาดควรแก้ไขอินสแตนซ์ชั่วคราวที่เฉพาะเจาะจงนี้ได้ เรียกใช้ BillingClient.queryPurchasesAsync() หลังจากได้รับ ITEM_NOT_OWNED เพื่อตรวจสอบว่าผู้ใช้ได้ ซื้อผลิตภัณฑ์หรือไม่ หากยังไม่ได้ดำเนินการ ให้ใช้ตรรกะการลองใหม่แบบง่ายเพื่อลองซื้ออีกครั้ง

การตอบกลับ BillingResult ที่เรียกข้อมูลซ้ำไม่ได้

คุณไม่สามารถกู้คืนจากข้อผิดพลาดเหล่านี้ได้โดยใช้ตรรกะการลองใหม่

FEATURE_NOT_SUPPORTED

ปัญหา

ข้อผิดพลาดที่ไม่สามารถลองใหม่นี้บ่งชี้ว่าฟีเจอร์ Google Play Billing ไม่รองรับในอุปกรณ์ของผู้ใช้ ซึ่งอาจเป็นเพราะ Play Store เวอร์ชันเก่า

เช่น อุปกรณ์ของผู้ใช้บางรายอาจไม่รองรับการรับส่งข้อความในแอป

การผ่อนปรนชั่วคราวที่อาจเกิดขึ้น

ใช้ BillingClient.isFeatureSupported() เพื่อตรวจสอบการรองรับฟีเจอร์ก่อนโทรไปยัง Play Billing Library

when {
    billingClient.isReady -> {
        val billingResult =
            billingClient.isFeatureSupported(BillingClient.FeatureType.IN_APP_MESSAGING)
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
            // use Feature
        }
    }
}

USER_CANCELED

ปัญหา

ผู้ใช้คลิกออกจาก UI ของโฟลว์การเรียกเก็บเงิน

การแก้ไขที่เป็นไปได้

ซึ่งเป็นเพียงข้อมูลและอาจล้มเหลวได้

ITEM_UNAVAILABLE

ปัญหา

การสมัครใช้บริการ Google Play Billing หรือผลิตภัณฑ์แบบซื้อครั้งเดียวไม่พร้อมให้ผู้ใช้รายนี้ซื้อ

การผ่อนปรนชั่วคราวที่อาจเกิดขึ้น

ตรวจสอบว่าแอปรีเฟรชรายละเอียดผลิตภัณฑ์ผ่าน queryProductDetailsAsync ตามที่แนะนำ พิจารณาความถี่ที่แคตตาล็อกผลิตภัณฑ์มีการเปลี่ยนแปลงในการกำหนดค่า Play Console เพื่อใช้การรีเฟรชเพิ่มเติมหากจำเป็น พยายามขายผลิตภัณฑ์ใน Google Play Billing ที่แสดงข้อมูลที่ถูกต้องผ่าน queryProductDetailsAsync เท่านั้น ตรวจสอบการกำหนดค่าการมีสิทธิ์ของผลิตภัณฑ์เพื่อดูความไม่สอดคล้องกัน เช่น คุณอาจค้นหาผลิตภัณฑ์ที่ใช้ได้เฉพาะใน ภูมิภาคอื่นที่ไม่ใช่ภูมิภาคที่ผู้ใช้พยายามซื้อ ผลิตภัณฑ์จะต้องอยู่ในสถานะใช้งานอยู่ จะต้องมีการเผยแพร่แอปของผลิตภัณฑ์นั้น และแอปจะต้องพร้อมให้บริการในประเทศของผู้ใช้เพื่อให้ผลิตภัณฑ์พร้อมจำหน่าย

บางครั้ง โดยเฉพาะอย่างยิ่งในระหว่างการทดสอบ การกำหนดค่าผลิตภัณฑ์อาจถูกต้องทุกอย่าง แต่ผู้ใช้ยังคงเห็นข้อผิดพลาดนี้ ซึ่งอาจเกิดจาก ความล่าช้าในการเผยแพร่รายละเอียดผลิตภัณฑ์ในเซิร์ฟเวอร์ของ Google โปรดลองอีกครั้ง ในภายหลัง

DEVELOPER_ERROR

ปัญหา

นี่คือข้อผิดพลาดร้ายแรงที่บ่งชี้ว่าคุณใช้ API อย่างไม่ถูกต้อง เช่น การระบุพารามิเตอร์ที่ไม่ถูกต้องให้กับ BillingClient.launchBillingFlow อาจทำให้เกิดข้อผิดพลาดนี้

การแก้ไขที่เป็นไปได้

ตรวจสอบว่าคุณใช้การเรียกใช้ Play Billing Library ที่แตกต่างกันอย่างถูกต้อง นอกจากนี้ ให้ตรวจสอบข้อความแก้ไขข้อบกพร่องเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อผิดพลาด