如何处理BillingClient.onBillingServiceDisconnected()?

问题描述 投票:0回答:4

最近我将我的一个应用程序迁移到 Google Play 应用内结算 v3。自发布以来,我仅在 Samsung 设备 上收到一些崩溃报告,这些报告都与

BillingClient.onBillingServiceDisconnected()
被调用有关。

当前代码如下所示:

val billingClient = BillingClient.newBuilder(context)
            .setListener(updatedListener)
            .enablePendingPurchases()
            .build()

billingClient.startConnection(
            object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        // The billing client is ready. You can query purchases here.
                        querySkuDetails()
                    }
                }

                override fun onBillingServiceDisconnected() {
                    // Try to restart the connection on the next request to
                    // Google Play by calling the startConnection() method.
                    initBilling() // all code here is wrapped in this method
                }
            }
)

我显然重新初始化了

BillingClient
并在错误情况下再次调用
startConnection()
。那么崩溃就是

java.lang.IllegalStateException: 
  at android.os.Parcel.createException (Parcel.java:2096)
  at android.os.Parcel.readException (Parcel.java:2056)
  at android.os.Parcel.readException (Parcel.java:2004)
  at android.app.IActivityManager$Stub$Proxy.registerReceiver (IActivityManager.java:5557)
  at android.app.ContextImpl.registerReceiverInternal (ContextImpl.java:1589)
  at android.app.ContextImpl.registerReceiver (ContextImpl.java:1550)
  at android.app.ContextImpl.registerReceiver (ContextImpl.java:1538)
  at android.content.ContextWrapper.registerReceiver (ContextWrapper.java:641)
  at com.android.billingclient.api.zze.zza (zze.java:5)
  at com.android.billingclient.api.zzd.zza (zzd.java:5)
  at com.android.billingclient.api.BillingClientImpl.startConnection (BillingClientImpl.java:58)
  at de.memorian.gzg.presentation.base.IAPHelper.initBilling (IAPHelper.java:40)
  at de.memorian.gzg.presentation.base.IAPHelper$initBilling$1.onBillingServiceDisconnected (IAPHelper.java:53)
  at com.android.billingclient.api.BillingClientImpl$zza.onServiceDisconnected (BillingClientImpl.java:11)
  at android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2060)
  at android.app.LoadedApk$ServiceDispatcher$RunConnection.run (LoadedApk.java:2099)
  at android.os.Handler.handleCallback (Handler.java:883)
  at android.os.Handler.dispatchMessage (Handler.java:100)
  at android.os.Looper.loop (Looper.java:237)
  at android.app.ActivityThread.main (ActivityThread.java:7857)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1076)
Caused by: android.os.RemoteException: 
  at com.android.server.am.ActivityManagerService.registerReceiver (ActivityManagerService.java:16726)
  at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:2250)
  at com.android.server.am.ActivityManagerService.onTransact (ActivityManagerService.java:3357)
  at android.os.Binder.execTransactInternal (Binder.java:1021)
  at android.os.Binder.execTransact (Binder.java:994)

我想知道我在

onBillingServiceDisconnected()
中做错了什么,所以我在谷歌上搜索了一段时间,没有找到任何明确的建议,但
// implement your own retry logic
。那是例如Google 说什么。这里的重试逻辑到底是什么?正如您在堆栈跟踪中看到的那样,按照 Google 评论的建议,再次调用
startConnection()
会导致崩溃。 这里 Google 说我应该忽略它,因为 Play 服务最终会稍后调用
onBillingSetupFinished()

您如何处理此案?

android google-play-services in-app-billing
4个回答
10
投票

没有找到我的问题如何处理失败案例的具体答案。我重构了我的代码,所以我基本上忽略了对

onBillingServiceDisconnected()
的调用,只向用户显示错误消息。

现在每次尝试购买时都会检查是否

  • BillingClient
    已初始化
  • BilligClient
    ready
  • Sku详情不为空

只有在这些成功后才尝试购买。

以前我在应用程序初始化中执行过一次以上所有操作。如果连接失败,现在,当用户再次单击购买项目时,我将简单地重试(使用 try catch)。这可能无法解决崩溃问题,但至少可以为用户提供更好的体验和控制。


2
投票

我也在我的 Google Play 仪表板中收到了类似的堆栈跟踪,但不是崩溃,而是 ANR。我解决这个问题的方法是将重新初始化计费的调用移至后台线程。

请注意,当有连接时会调用

onBillingServiceDisconnected
,但它会丢失。您可以通过在应用程序打开时清除 Google Play 的数据来进行测试。如果此时不重试,连接将会丢失。

当您尝试连接但失败时,会调用带有错误代码的

onBillingSetupFinished
。之前不存在任何联系。令人困惑的是,您还应该根据错误代码在此处重试。


1
投票

您可以通过实现

Retry
逻辑来处理 onBillingServiceDisconnected() 方法:

private static long reconnectMilliseconds = 1000;

@Override
public void onBillingServiceDisconnected() {
    retryBillingServiceConnection();
}

private void retryBillingServiceConnection() {
    new Handler().postDelayed(() ->
                    connectToBillingService(),
            reconnectMilliseconds);
    reconnectMilliseconds = reconnectMilliseconds * 2;
}

0
投票

这是 Google 的官方示例:https://github.com/android/play-billing-samples/blob/main/TrivialDriveKotlin/app/src/main/java/com/sample/android/trivialdrivesample/billing/计费数据源.kt

他们正试图以指数延迟重新连接:

private const val RECONNECT_TIMER_START_MILLISECONDS = 1L * 1000L
private const val RECONNECT_TIMER_MAX_TIME_MILLISECONDS = 1000L * 60L * 15L // 15 minutes
...
override fun onBillingSetupFinished(billingResult: BillingResult) {
    when (billingResult.responseCode) {
        BillingClient.BillingResponseCode.OK -> {
            // The billing client is ready. You can query purchases here.
            // This doesn't mean that your app is set up correctly in the console -- it just
            // means that you have a connection to the Billing service.
            reconnectMilliseconds = RECONNECT_TIMER_START_MILLISECONDS
            defaultScope.launch {
                querySkuDetailsAsync()
                refreshPurchases()
            }
        }
        else -> retryBillingServiceConnectionWithExponentialBackoff()
    }
}
...
/**
 * This is a pretty unusual occurrence. It happens primarily if the Google Play Store
 * self-upgrades or is force closed.
 */
override fun onBillingServiceDisconnected() {
    retryBillingServiceConnectionWithExponentialBackoff()
}
...
/**
 * Retries the billing service connection with exponential backoff, maxing out at the time
 * specified by RECONNECT_TIMER_MAX_TIME_MILLISECONDS.
 */
private fun retryBillingServiceConnectionWithExponentialBackoff() {
    handler.postDelayed(
            { billingClient.startConnection(this@BillingDataSource) },
            reconnectMilliseconds
    )
    reconnectMilliseconds = min(
            reconnectMilliseconds * 2,
            RECONNECT_TIMER_MAX_TIME_MILLISECONDS
    )
}
© www.soinside.com 2019 - 2024. All rights reserved.