整个应用中有一个BillingClient实例

时间:2018-11-02 02:03:57

标签: android in-app-purchase in-app-billing

我有一个包含许多活动的应用程序。活动之一是显示购买选项。

在计费库(https://github.com/googlesamples/android-play-billing)的示例应用程序中,使用BillingClientLifecycle和BillingManager,它们都与单个活动相关联,因此在创建/销毁活动时会打开/关闭连接。

但是,在具有许多活动的应用程序中,针对不同的活动单独执行此操作似乎并不理想。我还想在应用启动时检查订阅是否有效。

我正在考虑在应用程序的Application子类中创建BillingClient。但是,如果这样做,我只会打开BillingClient连接而不关闭它(因为那里没有onDestroy方法)。有人做过此事并且遇到任何问题吗?另外,这是否违反最佳做法,还会导致网络/性能出现任何问题吗?

6 个答案:

答案 0 :(得分:1)

看起来可以使用体系结构组件来完成。即在应用程序的OnCreate中,调用:

ProcessLifecycleOwner.get()。lifecycle.addObserver(billingClient)

然后将billingClient注入需要它的活动中。

答案 1 :(得分:1)

我通读了BillingClientImpl.javabilling-1.2.2-sources.jar的源代码,并且我相信将BillingClient用作应用程序单例是安全的,即使这意味着从不调用BillingClient.endConnection()

BillingClientImpl.java在其构造函数中不需要/使用Activity;它使用Context,而它所做的只是调用context.getApplicationContext()来存储应用上下文。 launchBillingFlow方法确实有一个Activity参数,但是没有存储活动。它的唯一目的是调用具有计费意图的activity.startActivity(intent)

BillingClient.startConnection调用context.registerReceiver将其自己的BillingBroadcastReceiver注册为BroadcastReceiver,然后调用context.bindService绑定服务连接。 (同样,这两个调用都是针对应用上下文mApplicationContext执行的,而不是针对任何特定的Activity执行的。)

只要在应用程序的生命周期内需要计费客户端,在registerReceiver中调用bindServiceApplication.onCreate()且从不调用unregisterReceiver是安全和可接受的或unbindService

如果registerReceiver和/或bindService调用使用Activity上下文,这将是不安全的,因为ServiceConnectionActivity被使用时会泄漏。已销毁,但是当销毁该应用程序时,其过程将终止,并自动清除其所有服务连接。

答案 2 :(得分:1)

关于计费库的更新的2.x版本,引自TrivialDriveKotlin官方演示应用BillingRepository来源的报价:

  

请注意,已建立与[playStoreBillingClient]的连接   使用applicationContext。这意味着实例不是   [活动]特定。而且由于它也不昂贵,因此可以保留   在整个[应用程序]的整个生命周期内都是开放的。所以不管是   为每个[活动]或[片段]创建(重新),或为   应用程序的寿命是一个选择问题。

我想这也适用于第一个版本。

答案 3 :(得分:0)

“我建议不要创建一个 Singleton类,该类从中提供BillingClient,并通过应用程序类进行初始化。”

为什么?因为这样做会在使用整个应用程序时泄漏内存或对象。


另一种方法是将此类制作为LifecycleObserver,这样一来,尽管您将其绑定到Activity/Fragment上,但仍然尊重它的生命周期,并相应地做事。

我已经创建了如下所示的类,并在我的一些项目中使用了(在其中,它运行良好)

查看以下课程:

  

InAppBilling.kt

class InAppBilling(val lifecycle: Lifecycle, purchasesUpdatedListener: PurchasesUpdatedListener) :
    LifecycleObserver,
    PurchasesUpdatedListener by purchasesUpdatedListener,
    BillingClientStateListener {

    companion object {
        const val TAG = "InAppBilling"
    }

    init {
        lifecycle.addObserver(this)
    }

    private var mBillingClient: BillingClient? = null

    private fun initClient(): BillingClient {
        return BillingClient
                .newBuilder(context) // You can provide application context here.
                .setListener(this)
                .build()
    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_CREATE)
    fun connectionToBillingServer() {
        mBillingClient = initClient()
        mBillingClient?.startConnection(this)
    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_DESTROY)
    fun disconnectFromBillingServer() {
        mBillingClient?.endConnection()
        lifecycle.removeObserver(this)
    }

    override fun onBillingServiceDisconnected() {
        if (lifecycle.currentState == Lifecycle.State.CREATED) {
            mBillingClient?.startConnection(this)
        }
    }

    override fun onBillingSetupFinished(responseCode: Int) {
        // Left out because "Unused"
    }
}

以及如何食用它:

要在Activity/Fragment中使用BillingClient的地方:

private var mBillingClient: InAppBilling? = null

//.. And inside of onCreate() method, you'll just need to initialize it like below:
    mBillingClient = InAppBilling(this@Activity.lifecycle, this)

现在,您可以使用此 billingClient对象从应用程序内客户端执行所需的操作。

您需要做的就是将您的特定方法添加到 InAppBilling类,并在所需的位置使用该方法。

this gist 中检出相同的班级

答案 4 :(得分:0)

进行BaseActivity,并让所有其他活动扩展基本活动。在BaseActivity中创建结算实例。

无需执行应用程序类。与在应用程序中一样,退出应用程序时不会收到事件。另外,如果将应用程序置于后台,则应用程序实例仍然存在,因此连接将保持不必要的打开状态。

答案 5 :(得分:-1)

BillingClient需要当前活动,因为它需要当前窗口令牌才能向用户显示购买对话框。因此,每次活动更改 window令牌时也会发生更改,因此您无法使用singleton类进行此操作,因为在singleton类中,您正在泄漏活动参考,并且还提供了一个 window令牌在您的应用会话中无效。