admin管理员组

文章数量:1123355

I developed a simple app without any backend cloud server, It has an IN-APP-Billing system for premium users. (It is a one-time purchase). To perform that system, I'm using Google's in-app billing library. When the user purchases, I made a preference value to true, that's how my users can access to the premium options of my app.

here's how I implemented it,

@AndroidEntryPoint
class MainActivity2 : ComponentActivity(), PurchasesUpdatedListener {

    @Inject
    lateinit var userPreferencesRepository: UserPreferencesRepository

    private lateinit var billingClient: BillingClient
    private val productId = "premium_features"

    @OptIn(ExperimentalPermissionsApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        billingClient = BillingClient.newBuilder(this)
            .setListener(this)
            .enablePendingPurchases()
            .build()

        startBillingConnection() // If I not call this method, purchase system is not working

        setContent {
            MainApp(
                onUpgradeSubmitClick = {
                    launchPurchaseFlow()
                }
            )

        }
    }

    private fun startBillingConnection() {
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    Toast.makeText(this@MainActivity2, "Billing Client Ready", Toast.LENGTH_SHORT).show()
                    // I never see this toast message
                }
            }

            override fun onBillingServiceDisconnected() {
                Toast.makeText(this@MainActivity2, "Billing Service Disconnected", Toast.LENGTH_SHORT).show()
                // I never see this toast message
            }
        })
    }

    private fun launchPurchaseFlow() {
        val params = QueryProductDetailsParams.newBuilder()
            .setProductList(
                listOf(
                    QueryProductDetailsParams.Product.newBuilder()
                        .setProductId(productId)
                        .setProductType(BillingClient.ProductType.INAPP)
                        .build()
                )
            )
            .build()

        billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsList ->
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && productDetailsList.isNotEmpty()) {
                val productDetails = productDetailsList[0]

                val purchaseParams = BillingFlowParams.newBuilder()
                    .setProductDetailsParamsList(
                        listOf(
                            BillingFlowParams.ProductDetailsParams.newBuilder()
                                .setProductDetails(productDetails)
                                .build()
                        )
                    )
                    .build()

                billingClient.launchBillingFlow(this, purchaseParams)
            } else {
                Toast.makeText(this, "Premium is not available", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (purchase in purchases) {
                handlePurchase(purchase)
            }
        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
            Toast.makeText(this, "Purchase canceled!", Toast.LENGTH_SHORT).show()
            lifecycleScope.launch{
                userPreferencesRepository.changePremiumStatus(false)
            }
        }
        else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED){
            Toast.makeText(this, "Welcome back to Premium!", Toast.LENGTH_SHORT).show()
            lifecycleScope.launch{
                userPreferencesRepository.changePremiumStatus(true)
            }
        }
        else {
            Toast.makeText(this, "Purchase failed!", Toast.LENGTH_SHORT).show()
            lifecycleScope.launch{
                userPreferencesRepository.changePremiumStatus(false)
            }
        }
    }

    private fun handlePurchase(purchase: Purchase) {
        Toast.makeText(this, "Welcome to Groovy Premium!", Toast.LENGTH_SHORT).show()
        lifecycleScope.launch{
            userPreferencesRepository.changePremiumStatus(true)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        billingClient.endConnection()
    }
}

It is working fine, I already have several users who purchase the premium option of my app. The main issue is, that some users are refunded their purchase amount but I don't build any system to recheck their purchase status and downgrade them. I googled it and searched it over this platform but I cant find any easy-to-implement solution that I implement without any API-based cloud server.

The library I'm using,

implementation("com.android.billingclient:billing:6.0.1")

Is there any system that I implement that can check the users purchase status and downgrade them if they refunded their purchase?

本文标签: kotlinHow to check the status of Inappbilling in android (Jetpack compose) appStack Overflow