BillingClient — queryProductDetailsAsync возвращает статусы ошибок (2, 6, 12) много раз.Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 BillingClient — queryProductDetailsAsync возвращает статусы ошибок (2, 6, 12) много раз.

Сообщение Anonymous »

Я использую платежный клиент в своей игре, чтобы люди могли покупать предметы в приложении.
Согласно моим журналам, многие пользователи не могут приобрести этот предмет, так как Поток покупок не запускается.
Журналы показывают, что большинство пользователей, запускающих поток покупок, "застревают" в методе queryProductDetailsAsync, что приводит к ошибкам:
int SERVICE_UNAVAILABLE = 2;

int ERROR = 6;

int NETWORK_ERROR = 12;
Дело в следующем что я использую queryProductDetailsAsync после успешного вызова startConnection — я не понимаю, почему это может быть ошибкой сети/соединения.
Согласно моим тестам, это всегда удается.Я также провел тест на телефоне своего друга, и он тоже прошел успешно.
Более того, я вижу некоторые успешные покупки некоторых пользователей.
Поэтому я предполагаю, что это не проблема конфигурации.< /p>
Все ошибки происходят из журналов, поступающих с устройств пользователей.
Вот код моего класса BillingHelper:

Код: Выделить всё

import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.android.billingclient.api.*
import com.android.billingclient.api.BillingFlowParams.ProductDetailsParams
import java.lang.ref.WeakReference

class BillingHelper
{
// region Enum

enum class PurchaseStatus
{
PURCHASED,
PENDING
}

// endregion

// region Companion

companion object
{
private const val TAG = "BillingHelper"
}

// endregion

// region Listener

interface BillingHelperListener
{
fun purchaseStatusUpdated(itemId: String, status: PurchaseStatus)
}

// endregion

// region Properties

private var billingClient: BillingClient? = null
private var context: WeakReference? = null
private var listener: BillingHelperListener? = null
private val handler = Handler(Looper.getMainLooper())

// endregion

// region Init

fun init(context: Context)
{
this.context = WeakReference(context)
}

fun setListener(listener: BillingHelperListener)
{
this.listener = listener
}

// endregion

// region Purchase flow

fun launchPurchase(activity: Activity, itemId: String, block: (purchaseStarted: Boolean) -> Unit)
{
KLog.i(TAG, "launchPurchase - $itemId")

connectToBillingClient { connected ->

KLog.i(TAG, "launchPurchase - $itemId. connected? - $connected")

if (connected)
{
prepareSkuForPurchase(activity, itemId, block)
} else
{
handler.post {

KLog.i(TAG, "launchPurchase - $itemId.  invoking false")
block.invoke(false)
}
}
}
}

private fun connectToBillingClient(block: (connected: Boolean) -> Unit)
{
KLog.i(TAG, "connectToBillingClient")

getBillingClient()?.let {

if (it.isReady)
{
KLog.i(TAG, "connectToBillingClient - already connected")
block.invoke(true)
return@let
}

it.startConnection(object : BillingClientStateListener
{
override fun onBillingSetupFinished(billingResult: BillingResult)
{
KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished")

if (billingResult.responseCode == BillingClient.BillingResponseCode.OK)
{
KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished - connected")
block.invoke(true)
return
}

KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished - invoking false")
block.invoke(false)
}

override fun onBillingServiceDisconnected()
{
KLog.i(TAG, "connectToBillingClient::onBillingServiceDisconnected - invoking false")
block.invoke(false)
}
})
}
}

private fun prepareSkuForPurchase(activity: Activity, itemID: String, block: (purchaseStarted: Boolean) -> Unit)
{
KLog.i(TAG, "prepareSkuForPurchase - $itemID")

val skuList = ArrayList()
skuList.add(itemID)

val productList =
listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId(itemID)
.setProductType(BillingClient.ProductType.INAPP)
.build()
)

val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)

getBillingClient()?.queryProductDetailsAsync(params.build()) { billingResult, skuDetailsList ->

KLog.i(TAG, "prepareSkuForPurchase::queryProductDetailsAsync - billing result - $billingResult")

/**
* PROBLEM IS HERE - ACCORDING TO THE LOG - IT SAYS:
*   1 - billing result - Response Code: ERROR, Debug Message: An internal error occurred.
*   2 - billing result - Response Code: NETWORK_ERROR, Debug Message: An internal error occurred.
*   3 - billing result - Response Code: SERVICE_UNAVAILABLE, Debug Message: Timeout communicating with service.
*/

var purchaseStarted = false

if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList.isNotEmpty())
{
launchSkuPurchase(activity, skuDetailsList[0])
purchaseStarted = true
}

handler.post {

KLog.i(TAG, "prepareSkuForPurchase::queryProductDetailsAsync - invoking purchase started? - $purchaseStarted")
block.invoke(purchaseStarted)
}
}
}

private fun launchSkuPurchase(activity: Activity, productDetails: ProductDetails)
{
KLog.i(TAG, "launchSkuPurchase - $productDetails")
val params = ProductDetailsParams.newBuilder()
params.setProductDetails(productDetails)
val billingFlowParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(listOf(params.build())).build()
getBillingClient()?.launchBillingFlow(activity, billingFlowParams)
}

private fun handleSuccessPurchase(purchase: Purchase)
{
KLog.i(TAG, "handleSuccessPurchase - $purchase")
KLog.i(TAG, "handleSuccessPurchase.  state = - ${purchase.purchaseState}")

if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED)
{
if (!purchase.isAcknowledged)
{
acknowledgePurchase(purchase)
} else
{
handler.post {

listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PURCHASED)
}
}
} else if (purchase.purchaseState == Purchase.PurchaseState.PENDING)
{
handler.post {

listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PENDING)
}
}
}

private fun acknowledgePurchase(purchase: Purchase)
{
KLog.i(TAG, "acknowledgePurchase - $purchase")

val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()

getBillingClient()?.acknowledgePurchase(acknowledgePurchaseParams) { result ->

KLog.i(TAG, ":acknowledgePurchase::status - ${result.responseCode}")

if (result.responseCode == BillingClient.BillingResponseCode.OK)
{
handler.post {

listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PURCHASED)
}
}
}
}

private val purchaseUpdateListener = PurchasesUpdatedListener { billingResult, purchases ->

KLog.i(TAG, "purchaseUpdateListener::onPurchasesUpdated : $billingResult")

if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && !purchases.isNullOrEmpty())
{
val purchase = purchases.first()
handleSuccessPurchase(purchase)
}
}

// endregion

// region Billing client

private fun getBillingClient(): BillingClient?
{
val context = this.context?.get() ?: return let {

KLog.i(TAG, "getBillingClient - context is null")
null
}

var billingClient = this.billingClient

if (billingClient == null)
{
KLog.i(TAG, "getBillingClient - creating new billing client")
billingClient = BillingClient.newBuilder(context)
.setListener(purchaseUpdateListener)
.enablePendingPurchases()
.build()

this.billingClient = billingClient
} else
{
KLog.i(TAG, "getBillingClient - using existing billing client")
}

return billingClient
}

// endregion
}
Как видите — проблема в методе queryProductDetailsAsync.
Что мне не хватает?
Я использую:
реализация 'com.android.billingclient:billing:7.0.0'

Подробнее здесь: https://stackoverflow.com/questions/788 ... -6-12-many
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»