Search Unity

Subscription Manager Docs clarification

Discussion in 'Unity IAP' started by jason416, May 3, 2020.

  1. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31
    Hi I've been going in circles for a while on this, basically trying to get Subscription Manager to detect if an Auto-renewable Subscription is currently active but will not auto-renew. I think I have tried every combination in the sandbox but nothing is working.

    From the docs:
    • isAutoRenewing() This returns a result to indicate whether this Product is auto-renewable.


    To me, "IsAutoRenewing" and "Is Auto-renewable" are not necessarily the same thing. Is this indicating if the product is an Auto-renewable type? Or is it indicating the status of the renewing subscription, ie if it will renew on expiry. In the docs it also says this: "Non-renewable Products in the Apple store return a Result. Unsupported value" which suggest that it does actually returning if the subscription is currently set to renew. However this is never returned to be true (at least in sandbox mode). Even when the sandbox subscription is renewing a random amount of times.



    • isCancelled() - Returns a Result enum to indicate whether this Product has been cancelled. A cancelled subscription means the Product is currently subscribed, but will not renew on the next billing date.

    This sound like what I'm look for instead of isAutoRenewing but if that's the case what is the point of isAutoRenewing()?



    • isSubscribed() and isExpired()
    Could it be possible I have to ignore the above and check if isSubscribed()= false and isExpired()=true? This I haven't yet tried but it seems very strange to have to do that given the other two options...

    Please what is the elusive combination I need to check?
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You would wan to test, as you are. However, you mention you want "to detect if an Auto-renewable Subscription is currently active but will not auto-renew", I'm not clear on how that would be possible? You mean if the renew attempts to withdraw from their bank, but there isn't sufficient funds, for example?
     
  3. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31
    Its a pretty common situation in the AppStore like this:
    User purchases a 1yr Auto renewable subscription. Halfway through the year they decide to cancel the subscription so it doesn’t auto renew when it expires. But since they already paid for the rest of the year the receipt should show that it’s not expired and will not renew but it’s still valid.

    It would appear that is the purpose of these two methods isCancelled() and isAutorenewable() but they don’t seem to work?
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Got it. I believe users are seeing different behavior in store testing vs a live game. What is the result of your testing so far?
     
    Last edited: May 6, 2020
  5. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31
    Ok so this is with the Apple App store not the GooglePlay store. I'm not finding in the sandbox mode that it ever returns that Autorenew is cancelled or turned off. As I understand, the Apple App Store during testing will renew the subscription a random amount of times between 0 and 6 before expiring. Even on the last time before it expires the subscription manager returns Autorenewable.true && isSubscribed.true && isCancelled.false && isExpired.false, in other words it's not giving any indication that it is about to stop renewing.

    If this is because I am in sandbox mode then that means this situation cannot be tested before going live, so I could really use a definitive explanation of the subscription manager use. And maybe isAutorenewable() could probably be renamed willAutoRenewOnExpiryDate() if that's actually what it does?
     
    Last edited: May 6, 2020
  6. SamOYUnity3D

    SamOYUnity3D

    Unity Technologies

    Joined:
    May 12, 2019
    Posts:
    626
    I think what you are looking for is the "Subscription Auto Renew Status" field. https://developer.apple.com/library....html#/apple_ref/doc/uid/TP40010573-CH106-SW1

    You need to get it from the Apple Store. https://developer.apple.com/documen...tore#//apple_ref/doc/uid/TP40010573-CH104-SW3
     
  7. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31

    Yes ok that seems like the right field. So I take it from your response that it is not implemented in the UnityIAP Subscription Manager Class or the IPurchaseReceipt Class?

    It seems like this should be included as it's pretty fundamental to subscriptions. It's also very confusing because SubscriptionInfo.isCancelled() seems like it should cover that condition.
     
  8. SamOYUnity3D

    SamOYUnity3D

    Unity Technologies

    Joined:
    May 12, 2019
    Posts:
    626
    The "none" values of ASN.1 are not exposed to apps, which means the value is only available to servers.
    upload_2020-5-18_14-35-13.png
     
  9. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31
    So does SubscriptionInfo.isCancelled() work in release then?

    Right now in Testflight and Sandbox mode the cancellation date from IPurchaseReceipt is always Cancellation Date: 0001-01-01 12:00:00 AM even for older sandbox purchases that have expired (perhaps Apple is somehow making the sandbox auto-renew expire without cancelling it).

    Additionally Subscription Manager never returns isCancelled.true or isExpired.true because when the sandbox subscription is not renewed, controller.products.all -> item.receipt becomes null immediately and subscription manager doesn't run. Is this the expected behaviour?
     
  10. SamOYUnity3D

    SamOYUnity3D

    Unity Technologies

    Joined:
    May 12, 2019
    Posts:
    626
    Could you provide a device log or screenshot with a cancellation date like "0001-01-01 12:00:00 AM "?

    Additionally Subscription Manager never returns isCancelled.true or isExpired.true because when the sandbox subscription is not renewed, controller.products.all -> item.receipt becomes null immediately and subscription manager doesn't run. Is this the expected behaviour?
    Yes, I did a similar test before and the results are the same as yours.
     
  11. jason416

    jason416

    Joined:
    Nov 8, 2018
    Posts:
    31
    So regarding the above, you're saying the expected behaviour is that SubscriptionInfo.isCancelled() and SubscriptionInfo.isExpired() methods will never ever return anything besides false? I must be missing something, why do they exist?


    Here are the debug logs from PurchaseProcessingResult. You can see the subscription renews 6 times automatically and then stops, but there is never a cancellation date.


    [FONT=Arial]********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:25:30 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002362
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:30:30 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:30:43 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002367
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:35:43 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:35:43 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002371
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    *******************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:40:43 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:40:43 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002370
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:45:43 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:45:43 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002363
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:50:43 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 3:50:43 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002360
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 3:55:43 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.
    ********************DEBUG MESSAGE: IPurchaseRECEIPT:
    ********************DEBUG MESSAGE: ProductID: MonthlySub
    ********************DEBUG MESSAGE: PurchaseDate: 2020-05-17 7:16:33 PM
    ********************DEBUG MESSAGE: Transaction ID: 1000000666002351
    ********************DEBUG MESSAGE: Apple OriginalTransactionID: 1000000663344578
    ********************DEBUG MESSAGE: Subscription Expiration Date: 2020-05-17 7:21:33 PM
    ********************DEBUG MESSAGE: Cancellation Date: 0001-01-01 12:00:00 AM
    ********************DEBUG MESSAGE: Quantity: 1
    ********************DEBUG MESSAGE: User had previous valid receipt, storing result.[/FONT]
     
  12. SamOYUnity3D

    SamOYUnity3D

    Unity Technologies

    Joined:
    May 12, 2019
    Posts:
    626
    The cancellation date is the time and date of the cancellation, for a transaction that was canceled by Apple customer support.

    You can cancel this subscription and see if the cancellation date changes.
     
  13. Harrishun

    Harrishun

    Joined:
    Apr 13, 2016
    Posts:
    59
    I am also finding this issue. On my initial implementation of our Restore Purchases feature, I noticed when testing that our app would flood the database with new entries for all previous transactions (which works out to be a lot since I've been using the same Apple test account for almost a year now). Initially I implemented a system that just checked whether we had already restored the product and then stopped further posts to the database, but as we move towards implementing purchasable, non-consumable and consumable items (up to this point we only had subscriptions), this "solution" will no longer be appropriate. I don't even think it was appropriate to begin with.

    As far as I can see, in Sandbox mode, when IAppleExtensions.RestoreTransactions gets called, it is calling ProcessPurchase with every single previous transaction, and there is nothing filtering out expired transactions. This is further shown when we reach our process which uses SubscriptionManager to check isSubscribed, isExpired and isCancelled. In this process we would assume that it would return isSubscribed = false and isExpired = true for an expired transaction, but it seems that it instead returns isSubscribed = true.

    I believe in our SubscriptionManager process we can check the current time against the result of getExpireDate, and then filter out expired transactions. I'll experiment with this and return with what I find, but it would be simpler if the above isSubscribed and isExpired worked, so hopefully this may give you guys at Unity a bit more idea of what's happening?

    Currently on: 2019.2.17f1, UnityIAP 2.0.6 (package manager)

    EDIT: I missed something there, I now see that isExpired and isCancelled returning false every time is expected behaviour. However, I would expect UnityIAP to not call ProcessPurchase on transactions that have had their expiry date elapsed. Is there any particular reason this isn't the case?
     
  14. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We don't explicitly call ProcessPurchase, that is done by the store API. We are a pass-through service only, and don't have control over this behavior.
     
    Harrishun likes this.
  15. Harrishun

    Harrishun

    Joined:
    Apr 13, 2016
    Posts:
    59
    Huh, I was under the impression that ProcessPurchase was a callback triggered by UnityIAP after it receives purchase data from the store. Good to know, appreciate it.
     
  16. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Correct, we don't "trigger it", we listen for it and expose it. The stores send it to us during the purchase and restore process.
     
    Harrishun likes this.