Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Catching a deferred downgrade before acknowledge expires

Discussion in 'Unity IAP' started by HART_SB, Jun 8, 2022.

  1. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    When downgrading from an annual subscription to a monthly one (both auto-renewals) we are using the default deferred payment with the IGooglePlayStoreExtensions.UpgradeDowngradeSubscription(current, new, GooglePlayProrationMode.Deferred) method.

    The all seems to work ok. When the next cycle comes around the new, lower-tier subscription picks up where the older subscription left off. It appears this only occurs if the IAP is initialised and the new purchase is acknowledged by PlayStore within a certain time frame (5min in test, and I think 3 days in production - not sure about the latter).

    My understanding of the IAP package is that this subscription handover can only be done when IAP is initialised, yeah? So, does this mean that if the subscription cycle rolls over, and then user doesn't use app for a week, then this subscription is cancelled and refunded? If so, is there any solution to acknowledge this purchase outside of running the app?

    I'm also having problems identifying the status of the deferred downgraded service prior to the subscription handover time (in my case Annual -> Monthly). Before this occurs, I need a way to visually display the Monthly services as 'already having been selected' in the UI. The SubscriptionManager data for the Annual subscription says isAutoRenewing == true and isCancelled == false so there's no indication that this deferred request has taken place.

    I used a 'SetDeferredPurchaseListener(NotifyUserOfOnDeferredSubscriptionChange)' when the API calls OnInitialized() but that doesn't seem to trigger anything (unless I'm using it wrong). I also tried using the IGooglePlayStoreExtensions.IsPurchasedProductDeferred(product) but that never seems to register a deferred product.
     
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @HART_SB No, all subscriptions are handled by Google servers. The upgrade process already acknowledges the purchase. Perhaps I'm not clear on what you mean by "handover" time. You say "appears", please be specific, check the test users Google account separately to confirm. To answer your question, no the subscription is not "cancelled" if the user does not launch the app.
     
  3. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    Thanks for the quick reply Jeff

    By 'handover', I mean the automatic behaviour when the Annual subscription finishes its cycle and downgrades to the previously selected Monthly subscription. Not a specific process, just the general behaviour. But this is where I get confused in the order and working of things.

    By 'upgrade process', I'm assuming you are you referring to when the ProcessPurchase() method is called for the deferred purchase - on first IAP initialisation after the aforementioned subscription handover/change takes place? What I am observing is that after this date rolls over, if I am not using the app for an extended period of time (and thus never initialising Unity IAP) then both the new subscription request AND the older subscription are being cancelled - because they have not been acknowledged.

    If I am understanding this correctly and this is the expected behaviour, wouldn't this result in a lot of unintended subscription cancellations/refunds?
     
  4. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    I also noticed this from the PlayStore docs:

    "When a user upgrades, downgrades, or resignup from your app before the subscription expires, the old subscription is invalidated, and a new subscription is created with a new purchase token."

    This would be ideal. However we don't get a token, or any new receipt data, when performing a deferred subscription crossgrade request. Is this right, or perhaps I'm mistaken and I'm not catching it correctly?
     
  5. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, I was referring to the initial upgrade API call which should also acknowledge the purchase. But you may be right, I would need to test. Can you confirm the receipt purchaseState value during your testing?
     
  6. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    So just to be clear, when upgrading using GooglePlayStoreExtensions.UpgradeDowngradeSubscription(current, new, prorationMode) you would usually use one of the 'pay now' proration modes. The API behaves as you would expect. The payment window comes up, you confirm, and then the ProcessPurchase() method automatically runs and you would get receipt info and do all the normal data validation and persisting.

    For downgrading, GooglePlayProrationMode.Deferred is the recommended option. As it is deferred until the downgrading subscription (Annual) reaches the end of its cycle, the ProcessPurchase() method does not run at this point.

    When IAP initialises (during the period prior to end-of-cycle), the Annual subscription purchaseState is 'Purchased'. Furthermore, any calls to the store for the subscription product that I will be downgrading to (Monthly) return no receipt data (until the 'handover' date event happens).
     
  7. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes understood. Can you provide the purchaseState value during this process? You should see a ProcessPurchase on app launch after this transaction according to your description, or trigger a Restore by reinstalling. Then check purchaseState https://forum.unity.com/threads/google-play-iap-problem.1140367/#post-7351220
     
  8. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    I am checking the purchase state of product receipts during both the OnInitialisation() and ProcessPurchase() calls.

    When first purchasing an Annual subscription, the annual product's receipt received in ProcessPurchase() has a state of Purchased (0).

    When I requests a downgrade subscription to Monthly, no ProcessPurchase() is called. In fact, there is no feedback when submitting UpgradeDowngradeSubscription() when deferred.

    When I leave app, sign in and initialised IAP, the current Annual product's receipt is received in OnInitialisation() has a state of Purchased (0). There is no receipt received for the Monthly subscription yet. This behaviour continues until the 'handover'.

    When the handover period happens, I initalise IAP and OnInitialised() runs. It passes a receipt for new Monthly subscription, and no receipt for Annual. This Monthly receipt has a state of Purchased (0). ProcessPurchase() then runs with the deferred purchase of the Monthly subscription. That Monthly receipt has state of Purchased (0).

    The biggest anomoly I see here is when I get the first receipt for the deferred Monthly purchase (first OnInitialised() after the handover). The state is Purchased (0), but it hasn't gone through the ProcessPurchase() yet. I would expect this to be 2 or 4, no? Not that this helps my current issues - I need to see that Monthly deferred receipt before all of this.

    I checked out the thread that you linked but it looks like their issue was the state's enum value. How are they even getting the deferred receipt? This is where my problem lies.
     
  9. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Please see my previous post. If you reinstall the app (as a test), you should see ProcessPurchase. But you shouldn't return complete until purchaseState = 1 https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState In fact, if the transaction is indeed in Pending, you should see ProcessPurchase during every app launch. Again, as a test. And it is possible as you describe. If the user doesn't come back in a timely manner, they lose the transaction. For a typical deferred purchase, the user has 3 days to pay or it is refunded. Please keep in mind that you are the only user in several years to report this as a possible issue. I doubt that Google would implement a transaction type that expires if the user doesn't play the game for awhile though.
     
  10. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    Still not sure if I'm understanding you. PurchaseState (1) = Cancelled, no?

    upload_2022-6-14_15-26-54.png

    To be clear, this is the purchaseState value I am getting from the Google receipt when validating.

    If I exit, delete, reinstall app. Upon initialization, the ProcessPurchase() is called for my existing Annual subscription and that has a purchaseState of 0. If I add a check of !=1{return Pending} then the existing product just loops initialisations and eventually gets cancelled by the store due to no acknoledgements.

    Looking at the docs, it looks like ProcessPurchase shouldn't run until after the payment goes through. In the deferred case, the payment is deferred until the end of the current cycle. So this makes sense as to why I am not seeing any deferred purchases. Maybe I missed your point?
    upload_2022-6-14_15-52-7.png

    Ignoring my fringe case of 'catching the handover', is there any way of seeing products that are in this waiting state (i.e. in line to change group tier at the end of the current cycle)? I basically want some way to indicate in the UI that this change in subscriptions is going to happen. This way, the user has visual confirmation they have already made the change request. Any suggestions?
     
    Last edited: Jun 14, 2022
  11. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sorry I don't have any suggestions. That diagram is old, prior to deferred purchases. ProcessPurchase can certainly trigger before payment goes through. You are expecting your users to downgrade purchases? Are you just testing, or are you actually seeing issues. And what do you mean "acknowledged when IAP starts". That only happens when ProcessPurchase is triggered, and Complete is returned.
     
  12. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    Thanks for the replies, I appreciate your patience. I'm trying to really determine my options here.

    I am wanting to become familiar with the features and limitations of Unity's IAP and this seems like a grey area in the documetation. We're just testing at the moment so nothing is live but deferring purchases to the end of subscription cycle is a use case we want to handle (deferred upgrades for instance) - after all, the feature's there.

    You're telling me it's supposed to do something and I'm trying to tell you that this is not happening. I use the method below and am setting payments as deferred but it's not prompting a ProcessPurchase() call.

    Code (CSharp):
    1. UpgradeDowngradeSubscription(currentSubscriptionId, newSubscriptionId, GooglePlayProrationMode.deferred);
    When I request the downgrade via this API, I get an email from Google saying the downgrade has been actioned - so it is going through to the Store. Similar thing happens if you are upgrading up a tier. What do I need to do on my end to prompt this ProcessPurchase() being called for the deferred purchase? This is the correct process for upgrades/downgrades, yeah?

    This diagram is from the latest Unity IAP docs 4.1.5. Is there another diagram I should be aware of? It would be very beneficial to see a deferred payment flow diagram.

    I don't recall saying this so not sure what you're asking.

    Sorry to keep badgering the point, I'm just not understanding how the deferred architecture works (or at least is supposed to work).
     
  13. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @HART_SB Correct, the upgrade/downgrade itself does not trigger a ProcessPurchase and would not be expected to. But you can trigger one as described. But it should not be needed, I was only requesting the purchaseState from the receipt. We don't have a deferred flow chart, it's a new option from Google. But I believe the deferred definition is different here. An actual deferred purchase occurs when the user chooses the option during checkout, and then has 3 days to pay at a physical location approved by Google. That does trigger ProcessPurchase, multiple ones. That is different from the deferred definition here. And you did mention "acknowledged when IAP starts" in your first post - "It appears this only occurs if the IAP is initialised and the new purchase is acknowledged by PlayStore within a certain time frame." We don't do any custom acknowledgment of transactions when IAP starts. For additional information on this transaction type, I would recommend that you reach out to Google.
     
  14. HART_SB

    HART_SB

    Joined:
    Nov 27, 2018
    Posts:
    16
    Sorry, I was searching for the quote verbatim. What I mean in my original post was that when this handover happens at the Store level, I get an email saying the new Monthly subscription has started. When I next initialise Unity IAP, the Store presumably recognises my Google account signed-in and 'acknowledges' the handover purchase. Then ProcessPurchase is called. If I don't to this (initalise IAP with my Google account signed-in) after a certain amount of time, the entire subscriptin is cancelled.

    I don't know how to trigger one. My understanding was that the Stores trigger this.

    All good though. I'm hearing what you're saying and I can't do what I want in this instance. Thanks for helping me understand IAP a bit better.

    Will be interesting to see if Unity expands this functionality into it's IAP package in the future. After all, they're using it in their v4.1.5 Sample examples (see screenshot) so without supporting data to give the state of deferred purchases it's a bit of a tease.

    upload_2022-6-15_15-21-23.png
     
  15. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    I described earlier how to trigger a ProcessPurchase. And you just said you do too! "Then ProcessPurchase is called" This is not a deferred purchase (where the user is required to pay at a physical store with real money), this is deferred proration, a different definition. It could be a Google bug, https://github.com/dooboolab/react-native-iap/issues/888 . It could be an actual issue, but you are the first one to report it. It could be that very few if anyone is offering downgrades. I might suggest to revisit the issue when IAP is updated with their updated billing library v5 later this year. But since you don't actually plan to use this feature, this is more of an XY problem at this point!