How to confirm the purchase correctly in Google Billing?

74 Views Asked by At

Purchases are returned to users after a few hours. How to confirm the purchase correctly?

"Your app should process a purchase in the following way:

Verify the purchase. Give content to the user, and acknowledge delivery of the content. Optionally, mark the item as consumed so that the user can buy the item again. To verify a purchase, first check that the purchase state PURCHASED"

class MainActivity : AppCompatActivity(), PurchasesUpdatedListener {

    private lateinit var bind: ActivityMainBinding
    private lateinit var billingClient: BillingClient

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        bind = DataBindingUtil.setContentView(this, R.layout.activity_main)
        setSupportActionBar(bind.toolbar)

        val params = ConsentRequestParameters
            .Builder()
            .setTagForUnderAgeOfConsent(false)
            .build()

        consentInformation = UserMessagingPlatform.getConsentInformation(this)
        consentInformation.requestConsentInfoUpdate(
            this,
            params,
            {
                UserMessagingPlatform.loadAndShowConsentFormIfRequired(
                    this@MainActivity
                ) { loadAndShowError ->
                    if (loadAndShowError != null) {
                        Log.w(
                            Constants.TAG, String.format(
                                "%s: %s",
                                loadAndShowError.errorCode,
                                loadAndShowError.message
                            )
                        )
                    }

                    if (consentInformation.canRequestAds()) {
                        initializeMobileAdsSdk()
                    }
                }
            },
            { requestConsentError ->
                // Consent gathering failed.
                Log.w(
                    Constants.TAG, String.format(
                        "%s: %s",
                        requestConsentError.errorCode,
                        requestConsentError.message
                    )
                )
            })
        if (consentInformation.canRequestAds())
            initializeMobileAdsSdk()

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

    }


    // обновление информации о покупках
    override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
        billingClient = BillingClient.newBuilder(App.instance)
            .setListener(this)
            .enablePendingPurchases()
            .build()

        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (purchase in purchases)
                handlePurchase(purchase)
        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
            showMessage(getString(R.string.snackbar_reset_app))
            SharedPreferencesManager.isFullVersion = true
        } else handleBillingError(billingResult.responseCode)
    }


    // установка соединения с google play для покупок
    private fun establishConnection() {
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    getSingleInAppDetail()
                } else retryBillingServiceConnection()
            }

            override fun onBillingServiceDisconnected() {
                retryBillingServiceConnection()
            }
        })
    }


    // повторное соединение с google play для покупок
    private fun retryBillingServiceConnection() {
        var tries = 1
        val maxTries = 3
        var isConnectionEstablished = false

        do {
            try {
                billingClient.startConnection(object : BillingClientStateListener {
                    override fun onBillingServiceDisconnected() {
                        retryBillingServiceConnection()
                    }

                    override fun onBillingSetupFinished(billingResult: BillingResult) {
                        tries++
                        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK)
                            isConnectionEstablished = true
                        else if (tries == maxTries)
                            handleBillingError(billingResult.responseCode)
                    }
                })
            } catch (e: Exception) {
                tries++
            }
        } while (tries <= maxTries && !isConnectionEstablished)

        if (!isConnectionEstablished)
            handleBillingError(-1)
    }


    // список доступных покупок
    private fun getSingleInAppDetail() {
        val queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder()
                .setProductList(
                    listOf(
                        QueryProductDetailsParams.Product.newBuilder()
                            .setProductId(getString(R.string.billing_product_id))
                            .setProductType(BillingClient.ProductType.INAPP)
                            .build()
                    )
                )
                .build()

        billingClient.queryProductDetailsAsync(queryProductDetailsParams) { _, productDetailsList ->
            launchPurchaseFlow(
                productDetailsList[0]
            )
        }
    }


    // запуск покупки
    private fun launchPurchaseFlow(productDetails: ProductDetails?) {
        val productList = ArrayList<ProductDetailsParams>()
        productList.add(
            ProductDetailsParams.newBuilder()
                .setProductDetails(productDetails!!)
                .build()
        )

        val billingFlowParams = BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productList)
            .build()

        billingClient.launchBillingFlow(this, billingFlowParams)
    }


    // запуск покупки
    private fun handlePurchase(purchase: Purchase) {
        if (!purchase.isAcknowledged) {
            billingClient.acknowledgePurchase(
                AcknowledgePurchaseParams
                    .newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
                    .build()
            ) {
                for (pur in purchase.products) {
                    if (pur.equals(getString(R.string.billing_product_id), ignoreCase = true)) {
                        Log.d(Constants.TAG, "Purchase is successful")
                        Log.d(Constants.TAG, "Yay! Purchased")
                        showMessage(getString(R.string.snackbar_reset_app))
                        SharedPreferencesManager.isFullVersion = true

                        consumePurchase(purchase)
                    }
                }
            }
        }
    }


    // запуск покупки
    private fun consumePurchase(purchase: Purchase) {
        val params = ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.purchaseToken)
            .build()

        billingClient.consumeAsync(params) { _, s ->
            Log.d(Constants.TAG, "Consuming Successful: $s")
            Log.d(Constants.TAG, "Product Consumed")
        }
    }


    // обработка ошибок о покупках с google play
    private fun handleBillingError(responseCode: Int) {
        val errorMessage: String = when (responseCode) {
            BillingClient.BillingResponseCode.BILLING_UNAVAILABLE -> "Billing service is currently unavailable. Please try again later."
            BillingClient.BillingResponseCode.DEVELOPER_ERROR -> "An error occurred while processing the request. Please try again later."
            BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED -> "This feature is not supported on your device."
            BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> "You already own this item."
            BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> "You do not own this item."
            BillingClient.BillingResponseCode.ITEM_UNAVAILABLE -> "This item is not available for purchase."
            BillingClient.BillingResponseCode.SERVICE_DISCONNECTED -> "Billing service has been disconnected. Please try again later."
            BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE -> "Billing service is currently unavailable. Please try again later."
            BillingClient.BillingResponseCode.USER_CANCELED -> "The purchase has been canceled."
            else -> "An unknown error occurred."
        }
        Log.d(Constants.TAG, errorMessage)
    }

}
0

There are 0 best solutions below