Search Unity

[Unity IAP] On auto-renewing-subscription is auto-renewed in store, what happens in Unity IAP?

Discussion in 'Unity IAP' started by yoppon, Jan 22, 2019.

  1. yoppon

    yoppon

    Joined:
    Nov 19, 2016
    Posts:
    17
    I have some questions about Unity IAP's behaviour when auto-renewing-subscription is auto-renewed.
    Please help.

    1-1)In case not relaunching app, just make app foreground from background, Nothing happens?
    1-2)Will
    ProcessPurchase()
    called automatically for subscription product?
    1-3)Will subscription product is automatically renewed in
    IStoreController.products.all 

    without calling any refreshing method like
    FetchAdditionalProducts() 
    or
    RefreshAppReceipt()

    1-4)Needs
    FetchAdditionalProducts() 
    to reflect renewed subscription product?
    1-5)Needs
    RefreshAppReceipt() 
    to reflect renewed subscription product?(iOS)

    2)In case relaunching app,
    UnityPurchasing.Initialize()
    makes subscription items renewed by automatically calling
    ProcessPurchase()
    ?

    3)And what is the difference of behaviour between iOSAppStore and GooglePlayStore?

    Sorry for many questions.
     
    Last edited: Jan 22, 2019
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
  3. yoppon

    yoppon

    Joined:
    Nov 19, 2016
    Posts:
    17
    Thank you, I'll use SubscriptionManager.
     
  4. alexandros356

    alexandros356

    Joined:
    Dec 3, 2012
    Posts:
    105
    Hi, Is the Subscription Manager already validate the receipt? What happens when I call the IsSubscribed method or the IsCancel method? Should I validate the receipt anyway?

    Thanks
     
  5. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You need to validate the receipt each time, we don't do that for you.
     
  6. rodolfomoraes

    rodolfomoraes

    Joined:
    Jan 23, 2020
    Posts:
    1
    How to connect the apple user who paid with the user who registered in the game? I'm having trouble understanding how to know if the user logged into the app is up to date with the payment made with the user logged into the apple store.
     
  7. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    For security, you (the developer) can't (and shouldn't) know. The payment process is (only) between the user and the Apple store, and is secure.
     
  8. toycantando

    toycantando

    Joined:
    Feb 28, 2017
    Posts:
    3
    Good day

    How I can get the updated Receipt when the subscription is auto - renewed?
     
  9. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We are tracking an issue on iOS where the receipt goes missing during a subscription auto-renewal. I'm hoping that we can address this issue in the next or upcoming release. Are you on iOS or Android?
     
  10. toycantando

    toycantando

    Joined:
    Feb 28, 2017
    Posts:
    3

    Good Day Jeff

    I'm Testing on Android first, for some reason when the test subscription is done unity don't update the Receipt.
    Also I want know if I have to use the Google Play Billing Library:
    https://developer.android.com/google/play/billing/unity

    or with the last version from Unity IAP come with that?
    I'm try with both, but saddly the Receipt is not updated.
     
  11. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Please show the code that you are using to check. What fields are you checking? Are you using the SubscriptionManager? I have code like this in the Sample IAP Project. It's similar to the code mentioned here

    https://forum.unity.com/threads/improved-support-for-subscription-products.532811/

    https://forum.unity.com/threads/sample-iap-project.529555/

    Code (CSharp):
    1.  public void ListProducts()
    2.     {
    3.  
    4.         foreach (UnityEngine.Purchasing.Product item in m_StoreController.products.all)
    5.         {
    6.             if (item.receipt != null)
    7.             {
    8.                 MyDebug("Receipt found for Product = " + item.definition.id.ToString());
    9.             }
    10.         }
    11.     }
     
  12. toycantando

    toycantando

    Joined:
    Feb 28, 2017
    Posts:
    3
    Hello Jeff

    this is the code to check the receipts:

    Code (CSharp):
    1.  
    2.  public void CheckProductsReceipts()
    3.     {
    4.         for (int i = 0; i < storeController?.products?.all?.Length; i++)
    5.         {
    6.             Debug.Log("PRINT RECEIPTS " + storeController?.products?.all?[i].receipt);
    7.  
    8.         }
    9.     }
    10.  
    this is the logcat from a monthly subscription test, I have that code inside the Update to validase if in any moment change:

    2021-02-17 17:53:45.255 31054-31076/? I/Unity: PRINT RECEIPTS {“Store":"GooglePlay","TransactionID":"hpigmidgggicgppmpmliopij.AO-J1OxZ0uloSRvQiSODGoKVgIdUDkRlhOiT6okWvGonsoTDguaGqdPRCGDzDSd0XQ5pcoDYvVNDn0VZESYO3dY2qAOF4ZMOJsSFS5FfHzAnCl9fR_XeBk0","Payload":"{\"json\":\"{\\\"orderId\\\":\\\"GPA.3343-7995-0582-09647\\\",\\\"packageName\\\":\\\"com.toycantando.myapp\\\",\\\"productId\\\":\\\"suscripcion_mes\\\",\\\"purchaseTime\\\":1613602219146,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"hpigmidgggicgppmpmliopij.AO-J1OxZ0uloSRvQiSODGoKVgIdUDkRlhOiT6okWvGonsoTDguaGqdPRCGDzDSd0XQ5pcoDYvVNDn0VZESYO3dY2qAOF4ZMOJsSFS5FfHzAnCl9fR_XeBk0\\\",\\\"autoRenewing\\\":true,\\\"acknowledged\\\":false}\",\"signature\":\"Y55nncjmII5PTgl0KEsRK9yJvKGDNm+fcJDsFhYALfwXkOaHlCJLGgkgLdbww22K8+bPtbRS3WfOjIc3E9f1cBYYIY8iBqKBWFyVtkVDEZwZ/TmAeYtVVRrZbl/oRZ4/hTVbG3TUT7AuiOCYqrogl4ES7JiEeYFg4fGhfcfW4emA6ev9c/XyvQUFifKYezX+3E+luUFdAkn3SCAUEGSiJqIETdWPWuq347viBMY2Oq+18UbaT+fG2wAcsxocz1HV5qn4uOC2S4pxuYc4MLmSr/GHd2oVQpPkPwu5/eF21LuyioCWsQxIa63k6523VyxwOcKehSLuketzNwxnsUsdbw

    Accord Google Documentation that auto renew happen each five mins, I validase in the console the order ids:

    GPA.3343-7995-0582-09647 , date: 17/2/2021 21:38 (UTC)
    GPA.3343-7995-0582-09647..0 date: 17/2/2021 21:43 (UTC)
    GPA.3343-7995-0582-09647..1 date: 17/2/2021 21:48 (UTC)

    but the product in unity never take that change.

    here is a "complete" code how i'm manager the renew:

    Code (CSharp):
    1.  
    2.  
    3. public  DateTime purchaseDate = default;
    4. public  DateTime subscriptionEndDate = default;
    5. public  Product currentSubscription = default;
    6. public  bool testEnviroment = true;
    7.  
    8. public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    9. {
    10. storeController = controller;
    11. #if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
    12.         validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), Application.identifier);
    13. #endif
    14.  appleExtensions = extensions.GetExtension<IAppleExtensions>();
    15.  googlePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
    16. }
    17.  
    18. private void Update{
    19. CheckProductsReceipts();
    20. isPremium = CheckSuscription();
    21. }
    22.  
    23.  
    24.     public void CheckProductsReceipts()
    25.     {
    26.         for (int i = 0; i < storeController?.products?.all?.Length; i++)
    27.         {
    28.             Debug.Log("PRINT RECEIPTS " + storeController?.products?.all?[i].receipt);
    29.                     if (storeController.products.all[i] != null && storeController.products.all[i].hasReceipt)
    30.         {
    31.             if (storeController?.products?.WithID(subscriptionMonth).receipt == storeController?.products?.all?[0].receipt)
    32.             {
    33.                currentSubscription = storeController.products.all[i];
    34.  
    35.             }
    36.         }
    37.         }
    38.  
    39. public bool CheckSuscription(){
    40. nowT = DateTime.UtcNow;
    41. #if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
    42.         // I use first the validator because the Google.Play.Billing don't get the subscription manager, so this methot to //get the Purchase date works with the UnityIAP and the Google.Play.Billing
    43.             if(validator != null) {
    44.                 var result = validator.Validate(currentSubscription.receipt);
    45.  
    46.                  foreach (IPurchaseReceipt productReceipt in result){
    47.                     PersistentData.purchaseDate = productReceipt.purchaseDate;
    48.                     Debug.Log("DATETIME PURCHASE DATE " + PersistentData.purchaseDate);
    49.                  }
    50.             }
    51.              if(testEnviroment == true){
    52.                  timeToAdd = 300;// 300s = 5min to match the test time of monthly subscription accord google      documentation
    53. subscriptionEndDate = purchaseDate.AddSeconds(timeToAdd).ToUniversalTime();
    54.  }else{
    55. timeToAdd = 1;// 1month
    56. subscriptionEndDate = purchaseDate.AddMonths(timeToAdd).ToUniversalTime();
    57.  
    58. }
    59.                
    60.                   remainingTime = PersistentData.subscriptionEndDate - nowT;
    61.                  Debug.Log(" END DATE " + subscriptionEndDate);
    62.                  Debug.Log(" REMAINING TIME " + remainingTime);
    63.            
    64. #endif
    65.    }
    66. }
    67.  

    Yes, I also use the subscription manager, but the purchase date never change, I beleive is because this take the real 30 Days instead the test time.

    Code (CSharp):
    1.  
    2.         if (storeController?.products?.all?.Length <= 0) { return; }
    3.  
    4.         if (Application.platform == RuntimePlatform.OSXPlayer)
    5.         {
    6.              introductory_info_dict = appleExtensions.GetIntroductoryPriceDictionary();
    7.         }
    8.         for (int i = 0; i < storeController.products.all.Length; i++)
    9.         {
    10.             if (storeController?.products?.all?[i].receipt != null)
    11.             {
    12.                 Debug.Log("SUBSCRIPCIONINF RECEIPT " + storeController?.products?.all?[i].receipt);
    13.                 if (storeController?.products?.all?[i].definition.type == ProductType.Subscription)
    14.                 {
    15.                     if (CheckSuscriptionAvailable(storeController?.products?.all?[i].receipt) == true)
    16.                     {
    17.                         string intro_json = (introductory_info_dict == null || !introductory_info_dict.ContainsKey(storeController?.products?.all?[i].definition.storeSpecificId)) ? null : introductory_info_dict[storeController?.products?.all?[i].definition.storeSpecificId];
    18.                         SubscriptionManager p = new SubscriptionManager(storeController?.products?.all?[i], intro_json);
    19.  
    20.                         SubscriptionInfo info = p.getSubscriptionInfo();
    21.                         subscriptionInfo = info;
    22.                     }
    23.  
    24.                 }
    25.                 else { Debug.Log("SUBSCRIPCIONINF the product is not a subscription product"); }
    26.             }
    27.             else { Debug.Log("SUBSCRIPCIONINF the product should have a valid receipt"); }
    28.  
    29.         }
    30.         if(subscriptionInfo != null)
    31.         {
    32.             Debug.Log("SUBSCRIPCIONINF " + subscriptionInfo);
    33.             Debug.Log("SUBSCRIPCIONINF SKU DETAILS " + subscriptionInfo.getSkuDetails());
    34.             Debug.Log("SUBSCRIPCIONINF purchase date  " + subscriptionInfo.getPurchaseDate());
    35.             Debug.Log("SUBSCRIPCIONINF is subscribed? " + subscriptionInfo.isSubscribed().ToString());
    36.             Debug.Log("SUBSCRIPCIONINF is Autorenewing? " + subscriptionInfo.isAutoRenewing().ToString());
    37.             Debug.Log("SUBSCRIPCIONINF Remaining time " + subscriptionInfo.getRemainingTime().TotalSeconds.ToString());
    38.             Debug.Log("SUBSCRIPCIONINF next billing date is: " + subscriptionInfo.getExpireDate());
    39.         }
    40.  
    logcat from SKU DETAILS:


    2021-02-17 18:15:47.336 31054-31076/? I/Unity: SUBSCRIPCIONINF SKU DETAILS {"productId":"suscripcion_mes","type":"subs","price":"COP 8,000.00","price_amount_micros":8000000000,"price_currency_code":"COP","subscriptionPeriod":"P1M","title":"suscripción Mensual","description":"accede a todo el contenido durante un mes”,"skuDetailsToken":"AEuhp4KkgDaNxp0Q5avRMoLyJvYJZxcYkFqP2geE4xckhMpIDYtkp0zkHPrSWZzxsRK_"}

    I'm not sure, if calling that metods inside the update maybe that causing the trouble. The reason I have that the Update is because I want see the moment when the change happens and be sure the timer is working fine.
     
  13. Beescott

    Beescott

    Joined:
    Oct 21, 2018
    Posts:
    2
    Hello Jeff.
    Is there a way to check whether the user is still subscribed after the auto-renewal? Since the receipt goes missing I have trouble finding a workaround.
     
    Dliix66 likes this.
  14. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    I'm not familiar with a work around, other than tracking dates yourself. We are working on this issue
     
  15. Beescott

    Beescott

    Joined:
    Oct 21, 2018
    Posts:
    2
    I'm sorry, I am not sure I understand how to track the dates. If I'm understanding well, the expiration date given by the SubscriptionManager gives the date of the end of the first subscription. How could we track the dates of the renewed subscriptions if we have no receipts of them?
     
  16. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yeah, good point. The assumption was that they successfully renew their subscription each month, but you would be blindly awarding the product which would be a non-starter, we are still working on this.
     
    Huy_Ng likes this.
  17. GameDevSK

    GameDevSK

    Joined:
    Jan 3, 2020
    Posts:
    3
    Can I use SubscriptionManager for both iOS and android?
    How can I change subscription time?
     
    Last edited: Jul 20, 2021
  18. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You can't change the subscription time. You mean like Weekly vs Monthly? You would need separate products.
     
  19. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    Did you found a solution for this issue? In Android it works perfectly, but in iOS when i use FetchAdditionalProducts for the subscription after an auto-renewal it seems the receipt doesn't get updated. Additionally, if i close the game and open after the expiration time for the first receipt i don't receive a receipt next time i enter the game.
     
  20. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    How are you using FetchAdditionalProducts? What if you front load all the products? Does the subscription show up during Restore?
     
  21. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    I currently load at start all the products, then fetch is called only for the auto-renewal subscription to update its receipt every 5 minutes (I'm aware it would be better to call the fetch once after the expiration occurs).

    Something i forgot to mention, this behavior is happening on testflight, so after 5 minutes the subscription expires (we are using a 1 month subscription).
     
  22. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You don't want to fetch products again if you've already loaded them. The method is only meant to be used as the name implies. I'll look forward to the Restore results
     
  23. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    In the documentation it says that FetchAdditionalProduct refresh metadata on existing products, in android i found this was the only way i got the receipt updated after it expired, maybe i understood wrong how it works. Even so, when closing and opening the app after a subscription expires it doesn't gets an receipt.

    PS. I'm working on getting the restore results, but will take a while.
     
  24. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    FYI Apple requires an IAP Restore button. If the subscription expires, you won't get a receipt.
     
  25. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    How can i get the expiration date for the next subscription cycle if i don't get a new receipt?
     
  26. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sorry I don't quite follow. If the subscription expires and they don't renew, there should not be a receipt. If they have an active or renewed subscription, the receipt should be available. We have heard of reports that receipts for autorenewing subscriptions go missing in Sandbox, seems to be an Apple issue. Should not occur in a released game.
     
    Last edited: Jul 20, 2021
  27. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    Sorry, let me try to explain better my issue:

    I have an auto-renewable subscription that renews monthly. I'm currently making tests in testflight and I'm seeing that when the first month (5 minutes in testflight) pass, if i close the app and then reopen the game there's no receipt, however since it is a renewable purchase it should have a receipt for the next month.

    Additionally, I'm seeing that when the time for the first month pass with the app open, the subscription gets Expired, this makes sense since the receipt only has as expiration date the end of the first subscription period, at this point i should update somehow the receipt to check for a new expiration date.

    How can i get that new expiration date for the next month if i don't receive a new receipt?
     
  28. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes it should. Please see my edited previous post.
     
  29. AlejandroMonascal

    AlejandroMonascal

    Joined:
    Jun 12, 2018
    Posts:
    8
    Thanks a lot for your answer
     
  30. Le-Tuan-Son

    Le-Tuan-Son

    Joined:
    Jan 13, 2016
    Posts:
    21
    As I know, if we call UnityPurchasing.Initialize at the start of the game, the receipt can be updated if subscription is auto-renewed.

    But if the game is opened when the subscription is auto-renewed. How can I get updated receipt? Does it automatically update? I just need to loop through IStoreController.products.all and these products have new receipt?
     
  31. komaltii22

    komaltii22

    Joined:
    Apr 12, 2022
    Posts:
    5
    Good day Jeff,

    I am recently working on auto renewable subscription based products. is this resolved as I am not getting solution to read particular receipt to restore and renewal purchase both for iOS and Android. Please help
    Thank you
     
    Last edited: Jan 10, 2023
  32. aVerrecchia

    aVerrecchia

    Unity Technologies

    Joined:
    Jun 28, 2022
    Posts:
    34
    Hello @komaltii22 !
    For now we rely on what purchases we retrieve to say if a subscription is entitled or not. Restoring transactions is a way to check if the product is still entitled.
    Our next major release (5.0.0) will include a way for our user to check a product entitlement status.
     
    komaltii22 likes this.
  33. prawn-star

    prawn-star

    Joined:
    Nov 21, 2012
    Posts:
    77
    Hello Jeff
    I don't think it's an apple issue. I have an app that has been around for a while (over 980 test subscription receipts worth) and I'fe just upgraded to Unity 2021.3.20 LTS and IAP 4.7.0.
    Test monthly subscription does. not automatically detect the renewed receipt after 5 mins. I have to press the subscribe button again and wait for the "You are already subscribed to this....." message.
    It all worked fine previously with Unity 2020.3.33 and IAP 4.5.2
    I don't just want to release an update in case it's NOT just an Apple Sandbox issue.
    Are you able to 100% confirm that actual real subscriptions won't go missing in store version?
     
  34. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    235
    Hello prawn-star,
    On Sandbox, there's the issue where the auto-renewal will not always work after the first time (new account or fresh purchase history), but this doesn't happen in production.

    Another thing is that Apple will only send the renewed subscription when foregrounding or restarting the application. In production, this occurs many hours ahead of the expiration time (when renewing) so it's usually not an issue, but on Sandbox this can happen within minutes, you can notice it easily.

    There shouldn't be any changes affecting this with the editor and IAP update you did.
     
  35. prawn-star

    prawn-star

    Joined:
    Nov 21, 2012
    Posts:
    77
    Hi Yannick_D

    Ok thanks for the update and reassurance. Just get a bit worried when there are updates from Unity and updates to iOS and then things that used to work stop (in Sandbox), Too many moving parts :)
     
    Laurie-Unity and Yannick_D like this.
  36. npaulsen

    npaulsen

    Joined:
    Jul 29, 2021
    Posts:
    2
    On iOS we are noticing a small amount of subscription receipts are going missing on renewal. We are seeing it most often with subscriptions that have free trials- probably because they renew the quickest.

    In support emails we print out the user's raw apple receipt information (from code the found here https://docs.unity3d.com/Manual/UnityIAPValidatingReceipts.html.) We also have an inconvenient way to fetch receipts through our backend from Apple. When we obtain the users receipts using our backend we can see the missing subscriptions are actually there.

    To us it's appearing like receipts in game are not always being correctly updated on renewal. Even having these people do a restore purchase doesn't seem to update the receipts in the game.

    We are using In App Purchasing 4.7.0. Any suggestions to what might be going on?
     
    Last edited: Apr 1, 2023
  37. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    235
    Hello npaulsen,

    For the receipt to update in-game, the app needs to receive the renewal transaction from Apple.
    However, we've noticed that this renewal transaction doesn't get sent until the application is reopened.
    This should only have an impact on short timed subscriptions, since regular ones will renew ahead of time.

    We are looking into this to offer a better solution to this problem.
     
  38. sasormb

    sasormb

    Joined:
    Apr 20, 2023
    Posts:
    4
    The 'Validate' function is not updating my expiration date on iOS for auto-renewal. On my Apple ID, I can see that the app has renewed and will expire in six months. However, within the app itself, the subscription shows as expired. When I call 'validate' it does not update my receipt and still displays an old expiration date. Is there any specific function we should call to update the receipts besides `validator.Validate(receiptData)`? Unity 2021.3.17f1
    Code (CSharp):
    1. ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
    2.                 IAppleConfiguration appleConfig = builder.Configure<IAppleConfiguration>();
    3.                 if (string.IsNullOrEmpty(appleConfig.appReceipt) == false)
    4.                 {
    5.                     byte[] receiptData = Convert.FromBase64String(appleConfig.appReceipt);
    6.                     AppleValidator validator = new AppleValidator(AppleTangle.Data());
    7.                     AppleReceipt localAppleReceipt = validator.Validate(receiptData);
    8.                     receipts = localAppleReceipt.inAppPurchaseReceipts;
    9.                 }
    Code (CSharp):
    1. for (int i = 1; i < receipts.Length; ++i)
    2.             {
    3.                     AppleInAppPurchaseReceipt receipt = (receipts[i] as AppleInAppPurchaseReceipt);
    4.                 if (IsAppleSubscriptionReceipt(receipt))
    5.                 {
    6.                     if (IsAppleSubscriptionReceipt(latestReceipt) == false)
    7.                     {
    8.                         latestReceipt = receipt;
    9.                     }
    10.                     else
    11.                     {
    12.                         DateTime receiptExpirationDate = receipt.subscriptionExpirationDate;
    13.                         DateTime latestExpirationDate = latestReceipt.subscriptionExpirationDate;
    14.                         if (receiptExpirationDate > latestExpirationDate)
    15.                         {
    16.                             latestReceipt = receipt;
    17.                         }
    18.                     }
    19.                 }