iOS Subscription Upgrade / Downgrade

We have been trying to implement subscription upgrade/downgrade on iOS for using Unity IAP [1.23.0] without success.

When subscribed on one of our subscription products (a monthly subscription) and trying to make a purchase on a second product (an annual subscription) from the same iOS group in iOS sandbox with IStoreController.InitiatePurchase, neither ProcessPurchase nor OnPurchaseFailed get called. We get stuck without being able to determine that the switch happened, although the subscription did change (as the ios auto_renew_product_id property of our receipt gets properly updated).

This post suggests that there is another way to do subscription upgrade/downgrade with SubscriptionManager.UpdateSubscription but I have been unable to use it on iOS as it does not trigger the purchase process.

How to properly implement subscription upgrade/downgrade on iOS with Unity IAP?

Have you tried using appleStoreCallback to process the purchase?

IGooglePlayStoreExtensions m_GooglePlayStoreExtensions;
m_GooglePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
Product oldProduct = m_Controller.products.WithID("oldProductID");
Product newProduct = m_Controller.products.WithID("newProductID");
Action<string, string> googlePlayCallback = new Action<string, string>(m_GooglePlayStoreExtensions.UpgradeDowngradeSubscription);
SubscriptionManager.UpdateSubscription(newProduct, oldProduct, "sampleDeveloperPayload", appleStoreCallback, googlePlayCallback);

The above code does not show how to use it on iOS. There is no equivalent extension in IAppleExtensions. Am I supposed to initiate a purchase after the callback is called?

I am confused about the same thing
@JeffDUnity3D any update on this?
@mradel did you make it work? or any work around? please help.

I will check, it seems it should be possible https://help.apple.com/app-store-connect/#/dev7f2d6b652

Hi, I would like to know this as well.

I’m using version 2.2.1 for the core (the one from Package Manager), and version 2.2.5 for the package (the one from Services). Using them on Unity 2019.2.21f1.

First purchase of a subscription has no issue, which I use
_storeController.InitiatePurchase(product)
to purchase.

When I detected that I have an existing subscription from the same group, I would then handle it with HandleSubscriptionUpgrade .

I tried 3 various methods, but none of them worked.

  1. calling SubscriptionManager.UpdateSubscriptionInAppleStore and do nothing with the appStoreUpdateCallback
protected override void HandleSubscriptionUpgrade(Product oldProduct, Product newProduct)
        {
            SubscriptionManager.UpdateSubscriptionInAppleStore(newProduct, null,
                (newProductArg, unknownArg) => Debug.Logger.Write($"ZR SUB: {newProductArg.definition.id}, {unknownArg}"));
        }

It returned the appleStoreUpdateCallback, with only newProductArg.
A native black transparent screen just stuck there, and I could no longer interact with my app.
I could see that my app was not frozen though.
Other than the native black screen, there was no native UI that show up like how it would be when you called _storeController.InitiatePurchase
getProductId: (omitted).ads.plan1,

getCancelDate: 0001/01/01 0:00:00

getExpireDate: 2020/12/17 9:04:00

getPurchaseDate: 2020/12/17 8:59:00

getRemainingTime: 00:04:43.9027980

isAutoRenewing: True

isCancelled: False

isExpired: False

isFreeTrial: False

isSubscribed: True

UnityIAPWrapper:HandleSubscriptions Old Subscription ((omitted).ads.plan1, True)

UnityIAPWrapper:HandleSubscriptions New Subscription ((omitted).ads.plan3, False)

ZR SUB: (omitted).ads.plan3,

  1. calling SubscriptionManager.UpdateSubscriptionInAppleStore and then call _storeController.InitiatePurchase(product) during the appleStoreUpdateCallback
        protected override void HandleSubscriptionUpgrade(Product oldProduct, Product newProduct)
        {
            SubscriptionManager.UpdateSubscriptionInAppleStore(newProduct, null, (newProductArg, unknownArg) =>
                _storeController.InitiatePurchase(newProductArg));
        }

This would return me error saying its a duplicate transaction.
The transaction ID is indeed the same as the old subscription purchased.
The new subscription was never succeeded.
And I’m not sure why is there a google message at the bottom.
getProductId: (omitted).ads.plan1,

getCancelDate: 0001/01/01 0:00:00

getExpireDate: 2020/12/17 8:37:23

getPurchaseDate: 2020/12/17 8:32:23

getRemainingTime: 00:04:31.3692750

isAutoRenewing: True

isCancelled: False

isExpired: False

isFreeTrial: False

isSubscribed: True

UnityIAPWrapper:HandleSubscriptions Old Subscription ((omitted).ads.plan1, True)

UnityIAPWrapper:HandleSubscriptions New Subscription ((omitted).ads.plan3, False)

2020-12-17 17:32:51.631714+0900 sikaq[5706:4385522] UnityIAP: PurchaseProduct: (omitted).ads.plan3

purchase({0}): (omitted).ads.plan3

2020-12-17 17:32:51.647538+0900 sikaq[5706:4385522] UnityIAP: UpdatedTransactions
…
(omitted)
…

2020-12-17 17:33:33.943237+0900 sikaq[5706:4385522] UnityIAP: UpdatedTransactions

2020-12-17 17:33:33.943452+0900 sikaq[5706:4385522] UnityIAP: DuplicateTransaction error with product (omitted).ads.plan3 and transactionId 1000000**(omitted)**

2020-12-17 17:33:33.944888+0900 sikaq[5706:4388132] - [I-ACS023141] Purchase is a duplicate and will not be reported. Product ID: (omitted).ads.plan3

onPurchaseFailedEvent({0}): productId:(omitted).ads.plan3 message:smile:uplicate transaction occurred

Failed to purchase (omitted).ads.plan3

Error: DuplicateTransaction

  1. call _storeController.InitiatePurchase(product) without going through SubscriptionManager.UpdateSubscriptionInAppleStore
        protected override void HandleSubscriptionUpgrade(Product oldProduct, Product newProduct)
        {
            _storeController.InitiatePurchase(newProduct);
        }

This resulted the same as method 2.
getProductId: (omitted).ads.plan1,

getCancelDate: 0001/01/01 0:00:00

getExpireDate: 2020/12/17 8:10:13

getPurchaseDate: 2020/12/17 8:05:13

getRemainingTime: 00:04:29.6287660

isAutoRenewing: True

isCancelled: False

isExpired: False

isFreeTrial: False

isSubscribed: True

UnityIAPWrapper:HandleSubscriptions Old Subscription ((omitted).ads.plan1, True)

UnityIAPWrapper:HandleSubscriptions New Subscription ((omitted).ads.plan3, False)

2020-12-17 17:05:43.372177+0900 sikaq[5660:4376061] UnityIAP: PurchaseProduct: (omitted).ads.plan3

purchase({0}): (omitted).ads.plan3

2020-12-17 17:05:43.388351+0900 sikaq[5660:4376061] UnityIAP: UpdatedTransactions

…
(omitted)
…

2020-12-17 17:06:22.099442+0900 sikaq[5660:4376061] UnityIAP: UpdatedTransactions

2020-12-17 17:06:22.099597+0900 sikaq[5660:4376061] UnityIAP: DuplicateTransaction error with product (omitted).ads.plan3 and transactionId 1000000**(omitted)**

2020-12-17 17:06:22.100925+0900 sikaq[5660:4377823] - [I-ACS023141] Purchase is a duplicate and will not be reported. Product ID: (omitted).ads.plan3

onPurchaseFailedEvent({0}): productId:(omitted).ads.plan3 message:smile:uplicate transaction occurred

Failed to purchase (omitted).ads.plan3

Error: DuplicateTransaction

@s-tang You shared this code, can you share where this flow is documented? I’m not familar “calling SubscriptionManager.UpdateSubscriptionInAppleStore and then call _storeController.InitiatePurchase(product) during the appleStoreUpdateCallback.” The UpdateSubscription call should handle the new purchase

@JeffDUnity3D It wasn’t from any documentation. I was just trying it out, since Method 1 (just by calling UpdateSubscriptionInAppleStore) doesn’t worked.

I just tried calling UpdateSubscription . It failed with the same result of my Method 1.

        protected override void HandleSubscriptionUpgrade(Product oldProduct, Product newProduct)
        {
            SubscriptionManager.UpdateSubscription(newProduct, oldProduct, null,
                                   (newProductArg, unknownArg) => Debug.Logger.Write($"ZR SUB: {newProductArg.definition.id}, {unknownArg}"),
                                   null);
        }

Only a native black semi-transparent screen overlay on top of my app.
Nothing else related to the subscription happens.
The app still runs, but I can’t do anything with it, since the native overlay screen is blocking my input to the app.

Am I missing something? Like do I need to enter anything for the developerPayload parameter? I’m not entirely sure what should go in there, hence the null.

@s-tang We are looking into this and will hopefully have an answer early next year. I need to test this.

Hello everyone,

We don’t have a proper Upgrade/Downgrade feature for iOS, as @mradel mentioned, we don’t have it in IAppleExtensions.

It looks like we could make something based off a quick pass or research, it is supported on the native side: Auto-renewable Subscriptions - App Store - Apple Developer
Handling Subscriptions Billing | Apple Developer Documentation
iOS Subscription Upgrade / Downgrade

We could also make it including code to handle cancellation, such as: ios - Cancel auto-renewal subscriptions with Swift - Stack Overflow

We’re going to add a feature to do this on our backlog.

Sorry for the inconvenience that we don’t support this at this time, thanks for pointing it out, as we want to keep making our API better in the future.

This is disappointing. I wasted 2 weeks trying to figure out how to use UnityIAP, without a proper updated documentation. I had to read through a whole bunch of threads, tons of trials and errors.

I understand this may not be your fault, but it would be appreciate that if there’s a proper centralized updated documentation. And mention what features are not yet supported, so we can choose to adapt the plugin or not.

Its really a pain to use UnityIAP with a lot of information unknown. Its already version 2, yet it feel like a version 0…

I’m sorry if this feel like a rant, but its frustrating.

1 Like

hi @s-tang ,

Sorry for the inconvenience our documentation being out of date. We’re aware of the situation and we’ll be working on updating the documentation soon.

Any update on this, when unity might support this feature, Any work around found for this by anyone?

Hi everyone,
I’m trying to implement those upgrades but it’s not going well. Has anyone found a working solution to this problem?

Can you share the code you are using and any errors you might be receiving? What version of IAP?

I’m having the same issue doing this

SubscriptionManager.UpdateSubscriptionInAppleStore(newProduct, null, (newProductArg, unknownArg) =>
                _storeController.InitiatePurchase(newProductArg));

Is there anything to perform upgrade/downgrade?

We are still working on this to comply with Google Billing Library v4 and StoreKit2. Hopefully we will have more information later in Q1

Any updates on this?

Unfortunately this work has been delayed. Current ETA is Q3

Still planned for Q3?