17.6 C
New York
Monday, April 28, 2025

android: “You already personal this merchandise” error for consumable objects, instantly after reconnecting web for Unity IAP (v4.12.2) and Google Billing (v6.2.1):


Ask:

I am having a problem with In-App Purchases (IAPs) in Unity, particularly when utilizing Unity model 2022.3.55f1, Unity In-App Buying v4.12.2, and Google Billing v6.2.1 for a consumable product on the Google Play Retailer. .

Problematic conduct:

  1. I efficiently accomplished the acquisition of a consumable utilizing the “Check Card, All the time Cross”.

  2. Instantly after finishing the acquisition, I flip off the Web connection.

  3. I reconnect to the Web virtually instantly.

  4. When I attempt to buy the identical consumable immediately, I get the error: “You already personal this merchandise.”

  5. After ready a couple of minutes, I can efficiently buy the merchandise once more.

This problem seems to be associated to the transaction course of not finishing or absolutely synchronizing instantly after reconnecting to the Web. I do not know if that is the true conduct. Please assist me.

What I’ve tried:

  1. I made certain that Unity IAP is correctly initialized and configured.

  2. I checked Google Play Console for buy data and there are not any points from Google Play.

  3. App information and cache have been cleared, however the problem nonetheless persists.

Request for code help:

May anybody assist me perceive why this error happens instantly after reconnecting to the web and the way can I deal with this in my code? Right here is the present code to deal with purchases:

public partial class AndroidInAppPurchaseManager : StoreSpecificPurchaseManager IDetailedStoreListener, IRestorePurchaseListner
    {

        personal IGooglePlayStoreExtensions _googlePlayStoreExtensions;

        #area SINGLETON
        personal static readonly AndroidInAppPurchaseManager _instance = new(); // Singleton sample
        static AndroidInAppPurchaseManager() { }
        personal AndroidInAppPurchaseManager() { }
        public static AndroidInAppPurchaseManager Occasion => _instance;
        #endregion

        // Initialize In-App Buy system
        public new void InitializeInAppPurchaseSystem()
        {
            base.InitializeInAppPurchaseSystem();
            ConfigureIAPForPlayStore();
        }

        personal void ConfigureIAPForPlayStore() // Configuring Unity IAP for Google Play
        {
            if (IsInitialized) return;
            ConfigurationBuilder builder = ConfigurationBuilder.Occasion(StandardPurchasingModule.Occasion(AppStore.GooglePlay));
            
            builder.Configure()
                .SetServiceDisconnectAtInitializeListener(() =>
                {
                    ToastController.Occasion.ShowToastMessage("Unable to hook up with the Google Play Billing service.");
                })
                .SetQueryProductDetailsFailedListener((int retryCount) =>
                {
                    ToastController.Occasion.ShowToastMessage($"Failed to question product particulars {retryCount} instances.");
                })
                .SetDeferredPurchaseListener(OnDeferredPurchase);

            AddProductsToConfigurationBuilder(builder, gameProductsDictionary);
            UnityPurchasing.Initialize(this, builder);
        }

        // Add merchandise to IAP configuration
        protected override void AddProductsToConfigurationBuilder(ConfigurationBuilder builder, Dictionary productDict)
        {
            if (gameProductsDictionary == null || gameProductsDictionary.Rely == 0)
            {
                gameProductsDictionary = ProductManager.Occasion?.GetProducts();
            }

            foreach (var product in gameProductsDictionary.Keys)
            {
                if (!string.IsNullOrEmpty(product))
                {
                    builder.AddProduct(gameProductsDictionary(product).AndroidProductID, gameProductsDictionary(product).ProductType);
                }
                else
                {
                    CustomFirebaseAnalytics.RecordCrashlyticsException("Product secret is Null Or Empty in AddProductsToBuilder methodology");
                }
            }
        }

        #area Unity IAP Initialization
        public new void OnInitialized(IStoreController controller, IExtensionProvider extensions)
        {
            base.OnInitialized(controller, extensions);
            _googlePlayStoreExtensions = extensions.GetExtension();

            if (storeController == null || storeController.merchandise == null)
            {
                CustomFirebaseAnalytics.RecordCrashlyticsException("StoreController is Null On OnInitialized");
                return;
            }

            Product() merchandise = storeController.merchandise.all;
            if (merchandise == null)
            {
                Debug.LogWarning("Android Product is null on initialization.");
                return;
            }

            UpdatePricesForIAPProducts(merchandise, GetProductIdFromAndroidId);
            PlayerDataHandler.Occasion?.LoadPurchasedProduct();
            PlayerDataHandler.Occasion?.PerformLocalReceiptValidation(merchandise);
        }

        public new void OnInitializeFailed(InitializationFailureReason error)
        {
            base.OnInitializeFailed(error);
        }

        public new void OnInitializeFailed(InitializationFailureReason error, string message)
        {
            base.OnInitializeFailed(error, message);
        }
        #endregion

        #area Android Buy Course of
        public new PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
        {
            var productItem = purchaseEvent.purchasedProduct;
            FinalizePurchaseAndGrantReward(productItem);

            return PurchaseProcessingResult.Full; // Full the acquisition instantly
        }

        public new void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
        {
            base.OnPurchaseFailed(product, failureReason);
        }

        public new void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
        {
            base.OnPurchaseFailed(product, failureDescription);
        }

        protected override void FinalizePurchaseAndGrantReward(Product product)
        {
            var purchaseStatus = _googlePlayStoreExtensions.GetPurchaseState(product);

            swap (purchaseStatus)
            {
                case GooglePurchaseState.Bought:
                    if (product.definition.sort == ProductType.NonConsumable)
                    {
                        PlayerDataHandler.Occasion.SavePurchaseProduct(product.definition.id, true);
                    }
                    rewardsController.RewardPlayer(product.definition.id);
                    CustomFirebaseAnalytics.SetEvent(FirebaseAnalyticsEvents.IAP_PURCHASE_SUCCESS, product.metadata.localizedTitle, product.definition.storeSpecificId);
                    break;
                case GooglePurchaseState.Refunded:
                    rewardsController.UnrewardPlayer(product.definition.id);
                    PlayerDataHandler.Occasion.SavePurchaseProduct(product.definition.id, false);
                    break;
                case GooglePurchaseState.Deferred:
                    OnDeferredPurchase(product);
                    break;
                case GooglePurchaseState.Cancelled:
                    OnPurchaseFailed(product, PurchaseFailureReason.UserCancelled);
                    break;
            }
        }
        #endregion

        #area Deferred Buy Dealing with
        personal bool IsPurchasedProductDeferred(string productId)
        {
            var product = storeController.merchandise.WithID(productId);
            return _googlePlayStoreExtensions.IsPurchasedProductDeferred(product);
        }

        personal void OnDeferredPurchase(Product product)
        {
            ToastController.Occasion.ShowToastMessage($"Product {product.metadata.localizedTitle} Buy has been deferred. Full the transaction within the Play Retailer");
            CustomFirebaseAnalytics.SetEvent(FirebaseAnalyticsEvents.IAP_PURCHASE_DEFFERED, product.metadata.localizedTitle, product.definition.storeSpecificId);
        }
        #endregion
    }
}

Questions:

  1. Why do I get the “You already personal this merchandise” error instantly after reconnecting to the Web?

  2. Is there a delay in processing the acquisition or syncing the acquisition standing after I reconnect? How can I programmatically deal with this to permit a direct buy?

  3. Is there a means to make sure that Unity IAP correctly acknowledges and processes a brand new buy after reconnecting to the Web with out having to attend a couple of minutes?

Anticipated conduct:

I ought to be capable of full the acquisition of a consumable merchandise instantly after reconnecting to the Web, with out receiving the “You already personal this merchandise” error and with out ready for any delays.

I’m utilizing Unity 2022.3.55f1, Unity IAP v4.12.2 and Google Billing v6.2.1. Any assist or recommendations will probably be tremendously appreciated!

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles