Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Renewable Subscription Purchase Android Doubts

Discussion in 'Unity IAP' started by siddharth3322, Jan 2, 2018.

  1. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    After completing iOS related renewable products subscription purchase, I shifted towards Android version of subscription purchase for my application.
    Platform is different so few different things running so please help me to understand the overall procedure.

    1. Why I was getting per day payment written in purchase dialog box? I have set monthly in configuration page on Play Store.
      Screenshot_2018-01-02-17-42-19-852_com.android.vending copy.png
    2. Using tester account if I made purchase then any money get cut from Credit Card? Because directly purchase box asking for my Credit Card details so I am confused before moving further.
    3. For local receipt validation, in iOS I have used this code so what code I need for Play Store? Where I can look for it?
      Code (CSharp):
      1. if (!string.IsNullOrEmpty (appleConfig.appReceipt)) {
      2.             // local receipt verification
      3.             var receiptData = System.Convert.FromBase64String (appleConfig.appReceipt);
      4.             AppleReceipt receipt = new AppleValidator (AppleTangle.Data ()).Validate (receiptData);
      5.             foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
      6.  
      7.                 //                    Debug.Log("# server date: " + GameManager.Instance.ServerDate + " expire date: " + productReceipt.subscriptionExpirationDate);
      8.                 int result = DateTime.Compare (GameManager.Instance.ServerDate.Date, productReceipt.subscriptionExpirationDate.Date);
      9.                 if (result <= 0) {
      10.                     isSubscriptionRunning = true;
      11.                     Debug.Log ("Subscription Running - Curr Date: " + GameManager.Instance.ServerDate.Date + " Expire Date: " + productReceipt.subscriptionExpirationDate.Date);
      12.                 }
      13.  
      14.                 Debug.Log ("PRODUCTID: " + productReceipt.productID + " CURR DATE: " + GameManager.Instance.ServerDate + " PURCHASE DATE: "
      15.                     + productReceipt.purchaseDate + " EXPIRATION DATE: " + productReceipt.subscriptionExpirationDate);
      16.  
      17.                 //                    Debug.Log ("CURR DATE: " + GameManager.Instance.ServerDate);
      18.                 //                    Debug.Log ("PRODUCTID: " + productReceipt.productID);
      19.                 //                    Debug.Log ("PURCHASE DATE: " + productReceipt.purchaseDate);
      20.                 //                    Debug.Log ("EXPIRATION DATE: " + productReceipt.subscriptionExpirationDate);
      21.                 //                    Debug.Log ("CANCELDATE DATE: " + productReceipt.cancellationDate);
      22.             }
      23.  
      24.             if (isSubscriptionRunning)
      25.                 SubscriptionActivated ();
      26.  
      27.     }
     
    Last edited: Jan 2, 2018
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    siddharth3322 likes this.
  3. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    Thank you sir for quick reply.
    I have following questions based on your last post:
    1. why its displaying rs2900/day rather than per month?
    2. I got information about purchase time what to do. But on each application launch how to check subscription status? As like I shown in above code for iOS.
    3. Is their expiration time in Play Store receipt?
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Regarding 1) you would want to check with Google, we don't control that dialog. I will check on subscription handling on the Play Store and will follow up.
     
    siddharth3322 likes this.
  5. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    On Google Play, if the subscription is cancelled or expired, the product will be dropped from the list (null product). Also, the Day vs Month issue that you originally mentioned is due to the behavior of the Sandbox environment.
     
    siddharth3322 likes this.
  6. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    Okay now I moved one step ahead based on your side reply and few resources, I found in Unity forum.
    Specially this one: https://forum.unity.com/threads/how-do-i-track-auto-renewing-subscriptions.476293/

    I have divided code into two sections:
    1. At purchase time code for receipt validation
      Code (CSharp):
      1. // at purchase time subscription check
      2.     private void UnlockSubscriptionContent (PurchaseEventArgs e)
      3.     {
      4.         bool validPurchase = true; // Presume valid for platforms with no R.V.
      5.  
      6.         // Prepare the validator with the secrets we prepared in the Editor
      7.         // obfuscation window.
      8.         var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
      9.             AppleTangle.Data(), Application.identifier);
      10.  
      11.         try {
      12.             // On Google Play, result has a single product ID.
      13.             // On Apple stores, receipts contain multiple products.
      14.             var result = validator.Validate(e.purchasedProduct.receipt);
      15.             // For informational purposes, we list the receipt(s)
      16.             Debug.Log("Receipt is valid. Contents:");
      17.             foreach (IPurchaseReceipt productReceipt in result) {
      18.                 Debug.Log(productReceipt.productID);
      19.                 Debug.Log(productReceipt.purchaseDate);
      20.                 Debug.Log(productReceipt.transactionID);
      21.             }
      22.         } catch (IAPSecurityException) {
      23.             Debug.Log("Invalid receipt, not unlocking content");
      24.             validPurchase = false;
      25.         }
      26.  
      27.         if (validPurchase) {
      28.             // Unlock the appropriate content here.
      29.             SubscriptionActivated();
      30.         }
      31.  
      32.     }
    2. Each app launch time code for receipt validation

      Code (CSharp):
      1. // daily subscription check for running or not
      2.     private void CheckIfSubscriptionIsActive ()
      3.     {
      4.         bool isSubscriptionRunning = false;
      5.  
      6.         foreach (Product p in m_StoreController.products.all) {
      7.             GooglePurchaseData data = new GooglePurchaseData (p.receipt);
      8.  
      9.             if (p.hasReceipt) {
      10.                 Debug.Log (data.json.autoRenewing);
      11.                 Debug.Log (data.json.orderId);
      12.                 Debug.Log (data.json.packageName);
      13.                 Debug.Log (data.json.productId);
      14.                 Debug.Log (data.json.purchaseTime);
      15.                 Debug.Log (data.json.purchaseState);
      16.                 Debug.Log (data.json.purchaseToken);
      17.  
      18.                 if (data.json.productId.Equals (kProductIDWeeklySubscription) || data.json.productId.Equals (kProductIDMonthlySubscription))
      19.                     isSubscriptionRunning = true;
      20.             }
      21.         }
      22.  
      23.         if (isSubscriptionRunning)
      24.             SubscriptionActivated ();
      25.        
      26.     }
    I have following questions based on current understanding:
    • Is this only enough to check only product entry within fetched list of product purchase? for taking subscription activation related decision. Because in Apple store we are checking expiration time related field too.
    • I am running with Auto Renewable Subscription product purchase so definitely in background transaction will happen and app user will open his app later on. When he open the app, at that time ProcessPurchase even get called for that transaction / purchase. So at this point, how to decide we have to provide access based on subscription benefit? May be again time was passed to not allow him to provide access for subscription benefit.
    Hope for some quick reply for above and may be I can complete my implementation after this :)
     
  7. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @siddharth3322 You are on the right track, you may also have to keep track of the purchased items in local storage on the users device. Be sure to test these scenarios.
     
    siddharth3322 likes this.
  8. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    One more question, arise in my mind after actual implementation because I am thinking, I have not implemented in correct way.

    As like Apple Store, Play Store subscription purchase not returning subscriptionExpirationDate. Because of this, when you open the application, it can execute past trails of purchase - its auto-renewable subscription. Its become really difficult to judge through this whether currently active or not.
    But I have figure out following code for this purpose so please check this and reply back to me.

    Code (CSharp):
    1. // at purchase time subscription check
    2.     private void UnlockSubscriptionContent (PurchaseEventArgs e)
    3.     {
    4.         bool validPurchase = false; // Presume valid for platforms with no R.V.
    5.  
    6.         // Prepare the validator with the secrets we prepared in the Editor
    7.         // obfuscation window.
    8.         var validator = new CrossPlatformValidator (GooglePlayTangle.Data (),
    9.                             AppleTangle.Data (), Application.identifier);
    10.  
    11.         try {
    12.             // On Google Play, result has a single product ID.
    13.             // On Apple stores, receipts contain multiple products.
    14.             var result = validator.Validate (e.purchasedProduct.receipt);
    15.             // For informational purposes, we list the receipt(s)
    16.             Debug.Log ("Receipt is valid. Contents:");
    17.             foreach (IPurchaseReceipt productReceipt in result) {
    18.                 Debug.Log (productReceipt.productID);
    19.                 Debug.Log (productReceipt.purchaseDate);
    20.                 Debug.Log (productReceipt.transactionID);
    21.  
    22.                
    23. if (productReceipt.productID.Equals (kProductIDWeeklySubscription)) {
    24.                     DateTime purchaseExpireDate = productReceipt.purchaseDate.AddDays (GameConstants.WEEKLY_SUBSCRIPTION);
    25.                     int status = DateTime.Compare (purchaseExpireDate, DateTime.Today);
    26.                     if (status <= 0)
    27.                         validPurchase = true;
    28.                 } else if (productReceipt.productID.Equals (kProductIDMonthlySubscription)) {
    29.                     DateTime purchaseExpireDate = productReceipt.purchaseDate.AddDays (GameConstants.MONTHLY_SUBSCRIPTION);
    30.                     int status = DateTime.Compare (purchaseExpireDate, DateTime.Today);
    31.                     if (status <= 0)
    32.                         validPurchase = true;
    33.                 }
    34.             }
    35.         } catch (IAPSecurityException) {
    36.             Debug.Log ("Invalid receipt, not unlocking content");
    37.             validPurchase = false;
    38.         }
    39.  
    40.         if (validPurchase) {
    41.             // Unlock the appropriate content here.
    42.             SubscriptionActivated ();
    43.         }
    44.  
    45.         // hide loading...
    46.         showLoader = false;
    47.         Camera.main.SendMessage ("ActivateLoadingDialog", false, SendMessageOptions.DontRequireReceiver);
    48.     }

    Above code get executed when you made your purchase so I checked with current date. For daily activation checking, I have used other code that exist in previous messages.
    Is this work for me?

    Also you have mentioned, I can use local storage but this way is also difficult because I don't know exactly when subscription get expired.
    Please share your suggestion for this and please made proper document regarding this :)
     
    Last edited: Jan 30, 2018
  9. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, Google subscriptions are a bit different. If the product is returned during IAP Initialization for Google Play, the subscription is active. If the product is not returned, the subscription is inactive.
     
  10. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    @JeffDUnity3D Thanks for making this point more clear.
    But my question still you didn't replied.

    I was running with Auto-Renewable subscription purchase so definitely in background few transactions will happened.
    So when user open the application at that time how to decide whether subscription is currently running or not?

    As per my understanding, I have figured this kind of code so please check this and reply me if something went wrong.

    Code (CSharp):
    1. // at purchase time subscription check
    2.     private void UnlockSubscriptionContent (PurchaseEventArgs e)
    3.     {
    4.         bool validPurchase = false; // Presume valid for platforms with no R.V.
    5.  
    6.         // Prepare the validator with the secrets we prepared in the Editor
    7.         // obfuscation window.
    8.         var validator = new CrossPlatformValidator (GooglePlayTangle.Data (),
    9.                             AppleTangle.Data (), Application.identifier);
    10.  
    11.         try {
    12.             // On Google Play, result has a single product ID.
    13.             // On Apple stores, receipts contain multiple products.
    14.             var result = validator.Validate (e.purchasedProduct.receipt);
    15.             // For informational purposes, we list the receipt(s)
    16.             Debug.Log ("Receipt is valid. Contents:");
    17.             foreach (IPurchaseReceipt productReceipt in result) {
    18.                 Debug.Log (productReceipt.productID);
    19.                 Debug.Log (productReceipt.purchaseDate);
    20.                 Debug.Log (productReceipt.transactionID);
    21.  
    22.                 if (productReceipt.productID.Equals (kProductIDWeeklySubscription)) {
    23.                     DateTime purchaseExpireDate = productReceipt.purchaseDate.AddDays (GameConstants.WEEKLY_SUBSCRIPTION);
    24.                     int status = DateTime.Compare (purchaseExpireDate, DateTime.Today);
    25.                     if (status <= 0)
    26.                         validPurchase = true;
    27.                 } else if (productReceipt.productID.Equals (kProductIDMonthlySubscription)) {
    28.                     DateTime purchaseExpireDate = productReceipt.purchaseDate.AddDays (GameConstants.MONTHLY_SUBSCRIPTION);
    29.                     int status = DateTime.Compare (purchaseExpireDate, DateTime.Today);
    30.                     if (status <= 0)
    31.                         validPurchase = true;
    32.                 }
    33.             }
    34.         } catch (IAPSecurityException) {
    35.             Debug.Log ("Invalid receipt, not unlocking content");
    36.             validPurchase = false;
    37.         }
    38.  
    39.         if (validPurchase) {
    40.             // Unlock the appropriate content here.
    41.             SubscriptionActivated ();
    42.         }
    43.  
    44.     }
    I hope now sir you are getting my exact question :)
    Overall now I can say, I am at the end by getting your side proper help so really thanks for this.
     
  11. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, per your exact question, when the application starts, if the product shows up in the list of products, the subscription is active (and no need to check the receipt). If the auto-renewed subscription was cancelled for example, it won't show in the list of products. If the subscription is auto-renewed when the application is already running, you would see the active subscription the next time the app is relaunched (or IAP is re-initialized)
     
    Last edited: Jan 31, 2018
    siddharth3322 likes this.
  12. MorenoBralts

    MorenoBralts

    Joined:
    May 23, 2017
    Posts:
    19
    I just checked this with a test account on my Android app, however the receipt is still showing up after a restart while the subscription has already ended.

    Steps I did:
    1. Activate the subscription.
    2. See that the subscription is active because I have received a receipt with
    autoRenew
    set to
    TRUE
    .
    3. Close down the app.
    4. Cancel the subscription.
    5. Wait 5 mins since that is the amount of time our testing subscription needed to wait until it tries to renew.
    6. Verify that no subscription is active in the Google play enviroment.
    7. Open up game and see that the receipt is still present.
     
  13. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We are working to improve subscription support, and you should see these improvements in a soon upcoming release! You'll see a boolean IsSubScriptionActive flag for this purpose.
     
    siddharth3322 likes this.