11.6 C
New York
Friday, March 14, 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):


Query:

I’m going through a problem with in-app purchases (IAP) 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.

Downside Conduct:

  1. I efficiently accomplished the acquisition of a consumable merchandise utilizing the “Take a look at card, at all times approves”.

  2. Instantly after the acquisition is accomplished, I flip off the web connection.

  3. I reconnect the web virtually instantly.

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

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

This challenge appears associated to the transaction course of not totally finishing or syncing instantly after reconnecting to the web. I do not know if that is the precise behaviour. Please assist me.

What I’ve tried:

  1. I’ve ensured that Unity IAP is accurately initialized and arrange.

  2. Checked the Google Play Console for buy logs and there aren’t any points from Google Play’s aspect.

  3. Cleared app knowledge and cache, however the challenge persists.

Request for Code Help:

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

public partial class AndroidInAppPurchaseManager : StoreSpecificPurchaseManager IDetailedStoreListener, IRestorePurchaseListner
    {

        non-public IGooglePlayStoreExtensions _googlePlayStoreExtensions;

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

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

        non-public 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 connect with the Google Play Billing service.");
                })
                .SetQueryProductDetailsFailedListener((int retryCount) =>
                {
                    ToastController.Occasion.ShowToastMessage($"Failed to question product particulars {retryCount} occasions.");
                })
                .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's Null Or Empty in AddProductsToBuilder technique");
                }
            }
        }

        #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.kind == 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
        non-public bool IsPurchasedProductDeferred(string productId)
        {
            var product = storeController.merchandise.WithID(productId);
            return _googlePlayStoreExtensions.IsPurchasedProductDeferred(product);
        }

        non-public 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 does the “You already personal this merchandise” error happen instantly after reconnecting the web?

  2. Is there a delay in processing the acquisition or syncing the acquisition state after reconnecting, and the way can I deal with this programmatically to permit a right away buy?

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

Anticipated Conduct:

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

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

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles