Problem Upgrading Subscriptions on iOS

First, I would like to apologise if a similar thread exists, I have gone through a lot of them but I’m still stuck on this issue.

I’ve set up multiple auto renewable subscriptions on appstore connect and made sure that they are in the same subscription group.

When upgrading I’m checking to see if the user already has a subscription and based on that, when the subscription button is clicked (and confirmed) I try to update the subscription using this code:

Product newProductIos = m_StoreController.products.WithID(inAppSubscriptionId);
                Product oldProduct =
                    m_StoreController.products.WithID(GetHighestIndividualSubscriptionSubscribedAndNotCancelled());

                SubscriptionManager.UpdateSubscription(newProductIos, oldProduct, "payload",
                    delegate(Product newProductArg, string s) { m_StoreController.InitiatePurchase(newProductArg); }, null);

However, every time I try to upgrade the subscription, on the sandbox it just treats it as a new purchase.
Is there something I’m missing?
I’ve used the sample upgrade sample for Android and got that working, but on iOS I could not find anything similar.

EDIT: I’m using Unity IAP 4.0.3

It appears we may have an issue with subscription upgrades on iOS, we are working on this. No ETA yet at this time.

Is this related to sandbox or the entire upgrade process in general?
And is there an alternative?

In general, and I have no alternate suggestions unfortunately.

One more question, if on upgrade, I redirect to the app stores subscription page, and the user changes their subscriptions from there, would the older subscription give
subscriptionInfo.isCancelled() == Result.True?
If so that is something I could use to check if a subscription has been shifted or not.

You would want to test. Since you can reproduce, you can debug in XCode, the Debug.Log statements will display in the XCode console https://discussions.unity.com/t/700551 and https://discussions.unity.com/t/748729/14

Yup doing that.
But I really feel that it should be mentioned in the documentation that the upgrade functionality does not work on iOS. Right now there are two functions for upgrading subscriptions on iOS and they both don’t work.

So I added a bunch of debug logs for all properties that SubscriptionInfo gives. I subscribed to one subscription in the app and in the iOS’s sandbox subscription page subscribed to a different subscription. When I check the receipts the next time I open the apps I get two valid subscriptions. Even though I’ve made them part of the same subscription group.
Am I doings something wrong or is this an issue with IAP?

Subscription Details info.getProductId()) app.x.x.basic.365
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getPurchaseDate()) 10/7/2021 12:08:01 PM
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getExpireDate()) 10/7/2021 1:08:01 PM
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isSubscribed()) True
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isExpired()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isCancelled()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isFreeTrial()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isAutoRenewing()) True
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getRemainingTime()) 00:29:13.0279000
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isIntroductoryPricePeriod()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPrice()) not available
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPricePeriod()) 00:00:00
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPricePeriodCycles()) 0

Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getProductId()) app.x.x.pro.30
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getPurchaseDate()) 10/7/2021 12:37:36 PM
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getExpireDate()) 10/7/2021 12:42:36 PM
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isSubscribed()) True
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isExpired()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isCancelled()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isFreeTrial()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isAutoRenewing()) True
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getRemainingTime()) 00:03:48.0223100
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.isIntroductoryPricePeriod()) False
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPrice()) not available
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPricePeriod()) 00:00:00
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Subscription Details info.getIntroductoryPricePeriodCycles()) 0
Managers.Purchaser:RetrieveAllAndStoreAllSubscriptionInfo()
Managers.GameSubscriptionManager:ResponseGetSchoolDetails(Boolean, SchoolDetails)

As the logs state, both subscriptions are subscribed and not cancelled.
Reposted because I wanted to confirm the logs.

As replied already here https://discussions.unity.com/t/857678/2

Jeff, I really don’t understand this. On the documentation all of these fields are mentioned and no where does it say it does not work for iOS.
Regardless, can you give me some alternatives has to how better to parse the store receipt to get my required fields or is it something that is not to be trusted at all, and that I should not use Unity’s IAP for the whole process…

Also, are the product details received OnInitialized of IStoreListener?
My use case is such that I want to re-fetch all product receipts(/subscriptioninfo) when the app is brought back to the foreground. Would I need to Initialize the IStoreListener again or is there some alternative?

Sorry for the confusion, I had mentioned it above. It looks like a bug that we still need to look into.

Hey, I’ve run into another issue and I just wanted to ask if I’ve done something wrong, or is it another bug with the IAP package. On iOS is the restore purchases functionality buggy as well? I’ve used this code to restore transactions.
I’m using this for Auto Renewable subscriptions. I’m testing using Sandbox purchases, when I do a fresh install and it doesnt detect the subscription, I added this restore button to explicitly get the subscription.

        private void OnRestoreTransactionsClicked()
        {
#if UNITY_IOS

            appleStoreExtensions.RestoreTransactions(OnRestore);
#endif
        }

        void OnRestore(bool success)
        {
            var restoreMessage = "";
            if (success)
            {
                // This does not mean anything was restored,
                // merely that the restoration process succeeded.
                restoreMessage = "Restore Successful";
            }
            else
            {
                // Restoration failed.
                restoreMessage = "Restore Failed";
            }

            Debug.Log(restoreMessage);
        }

What my assumption here is that on restoration success, it will call the process purchase of the IStoreListener. But that’s not the result that I’m getting. It simply does nothing when I try to restore purchase.

IStoreListener? Are you using Codeless IAP? It sounds like you may be mixing Codeless and Scripted IAP. If you are using Codeless, you’ll just want to use the IAP Restore Button (not in code, like you have). If you are using Scripted IAP, please show your ProcessPurchase code.

I’m not using Codeless IAP. By IStoreListener I meant my implementation of the IStoreListener class.
This is what I have in my process purchase:

public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
        {
            // Retrieve the purchased product
            var product = args.purchasedProduct;

            Debug.Log($"Purchase Complete - Product: {product.definition.id}");

            switch (product.definition.id)
            {
                case GameConstants.InAppSubscriptionIds.BasicMonthlySubscriptionProductId:
                    Debug.Log("Basic Monthly Subscribed");
                    break;
                case GameConstants.InAppSubscriptionIds.BasicYearlySubscriptionProductId:
                    Debug.Log("Basic Yearly Subscribed");
                    break;
                case GameConstants.InAppSubscriptionIds.ProMonthlySubscriptionProductId:
                    Debug.Log("Pro Monthly Subscribed");
                    break;
                case GameConstants.InAppSubscriptionIds.ProYearlySubscriptionProductId:
                    Debug.Log("Pro Yearly Subscribed");
                    break;
            }
           
            SetPriceValues();

            RetrieveAllAndStoreAllSubscriptionInfo();
           
            string highestIndividualSubscriptionSubscribedTo = GetHighestIndividualSubscriptionSubscribedToEvenIfCancelled();
            GameSubscriptionManager.Instance.HighestIndividualSubscriptionSubscribedTo = highestIndividualSubscriptionSubscribedTo;
            UiEventsManager.Instance.OnIndividualSubscriptionPaidSuccessfully?.Invoke(highestIndividualSubscriptionSubscribedTo);

            isGetStoreDetailsComplete = true;
            LoaderDisplayManager.Instance.TurnOffAllLoaders();

            // We return Complete, informing IAP that the processing on our side is done and the transaction can be closed.
            return PurchaseProcessingResult.Complete;
        }

Please share your Debug.Log output. And could you try the same code here:

This should help getting the logs in XCode How To - Capturing Device Logs on iOS Also note that subscriptions in Sandbox expire in 5 minutes, and one user can only subscribe 6 times. So you need to be fast in your testing, and either use multiple products for testing, or multiple testers.