Subscription Questions



  • [Local Validation]

    So, I understood that SIS safely operates with subscription only with server-side validation.

    I understood that local validation can be hacked because system time can be changed easily, but not all users will change system time & try to hack the app.

    Therefore, I believe that base local validation of subscription without internet using checking of system time (utc) is NOT pointless. It will work good enough for some part of users.

    So it makes sense to be part of SIS.


    [Server-side Validation - Expiration Checking]

    If I check subscription activity using DBManager.isPurchased() then SIS automatically fetches info (when internet is on) about activity of subscription from App Store & Google Play through my own server & stores it in DBManager, right?

    1. If so, then why own server is needed? Why the app can't directly answer App Store & Google Play?
    2. Is there a way to check expiration of subscription without own Server when Internet is ON/OFF?
    3. How can I show subscription expiration date to user when Internet is ON/OFF?
    4. Can I use Local & Server Validation Together when internet is OFF and ON appropriately? So I just need to attach 2 validators on IAP Manager or there is more complex way?

    [Cancelling]

    1. How to implement "cancel subscription" button?


  • [Server-side Validation - Expiration Checking]
    If so, then why own server is needed? Why the app can't directly answer App Store & Google Play?

    You already answered it yourself really: "DBManager.isPurchased() fetches info [...] through my own server". Server-side receipt validation is secure because the server does it. Why would it be secure if the app does it? Also, receipt validation via Google and Apple requires secret keys. You don't want to distribute your publisher secret keys within your app to all users worldwide. See here and here.

    Is there a way to check expiration of subscription without own Server when Internet is ON/OFF?

    See next question.

    How can I show subscription expiration date to user when Internet is ON/OFF?

    Not via Simple IAP System. You have access to Unity IAP directly so you can use their SubscriptionManager, which provides this info after it is initialized.

    Can I use Local & Server Validation Together when internet is OFF and ON appropriately? So I just need to attach 2 validators on IAP Manager or there is more complex way?

    There can only be one ReceiptValidator script on the IAPManager. Additionally Simple IAP System does not include a reliable internet checker. These are paid assets, like this one. This is out of scope for our asset.

    [Cancelling]
    How to implement "cancel subscription" button?

    Impossible since it is not done in the app. See here and here.



  • @Baroni said in Subscription Questions:

    Can I use Local & Server Validation Together when internet is OFF and ON appropriately? So I just need to attach 2 validators on IAP Manager or there is more complex way?

    There can only be one ReceiptValidator script on the IAPManager. Additionally Simple IAP System does not include a reliable internet checker. These are paid assets, like this one. This is out of scope for our asset.

    It's not needed for paid asset, because Unity has own checker: Application.internetReachability

    So if I use only server-side validator, how it works when internet is off?



  • It's not needed for paid asset, because Unity has own checker: Application.internetReachability

    Not reliable. Note: Do not use this property to determine the actual connectivity.

    So if I use only server-side validator, how it works when internet is off?

    It doesn't. Receipts are not validated on app startup without internet.



  • If I uploaded file to domain.com/app/verify.php, then
    "app" folder & file itself must have 700 permission attributes, right?



  • Yes, that's right. Chmod 700 is the minimum.



  • You need to update ReceiptValidatorServer.cs because in Unity 2019.4.1:

    Assets/SimpleIAPSystem/Scripts/ReceiptValidatorServer.cs(158,13): warning CS0618: 'WWW' is obsolete: 'Use UnityWebRequest, a fully featured replacement which is more efficient and has additional features'



  • Update Request #2. Changes in Google Play.

    Check this news blog post and especially last paragraphs starting with "You may have to make modifications to your app or your server to handle these new features. Specifically, your app should... "

    Will subscription status still relevant with SIS Server Side receipt verification, or you need update your asset?



  • I set the only subscription in Google Play Console with Monthly Charging, but when I call purchase flow then Android 10 shows me native window with price per 5 min and NOT per month.

    Free Trial : Disabled,
    Introductory price: None,
    Grace period: 7 Days,
    Resubscribe: Enabled for Testers (By Default).

    What the issue?

    UPD: Answer.



  • How to fetch the subscription price with billing period or period separately?



  • @andrewio said in Subscription Questions:

    How to fetch the subscription price with billing period or period separately?

    The subscription price is the product price, you already know how to get that from the other thread.

    For the billing period you would access Unity IAP directly as well. This is not something we store in Simple IAP System products.

    https://forum.unity.com/threads/how-to-get-subscription-duration-or-billing-period-information-on-ios-and-android.655675/



  • I saw that when server side validation then manual has message:

    "Play-test your server verification process on the actual device with “Development Build” logging enabled."

    What about fake testing in editor? I got an error:

    NullReferenceException: Object reference not set to an instance of an object
    SIS.ReceiptValidatorServer.Validate (UnityEngine.Purchasing.Product p) (at Assets/SimpleIAPSystem/Scripts/ReceiptValidatorServer.cs:95)
    SIS.IAPManager.ProcessPurchase (UnityEngine.Purchasing.PurchaseEventArgs e) (at Assets/SimpleIAPSystem/Scripts/IAPManager.cs:441)
    UnityEngine.Purchasing.StoreListenerProxy.ProcessPurchase (UnityEngine.Purchasing.PurchaseEventArgs e) (at <e647153c046145fb94ba309b1e626b12>:0)
    UnityEngine.Purchasing.PurchasingManager.ProcessPurchaseIfNew (UnityEngine.Purchasing.Product product) (at <e647153c046145fb94ba309b1e626b12>:0)
    UnityEngine.Purchasing.PurchasingManager.OnPurchaseSucceeded (System.String id, System.String receipt, System.String transactionId) (at <e647153c046145fb94ba309b1e626b12>:0)
    UnityEngine.Purchasing.JSONStore.OnPurchaseSucceeded (System.String id, System.String receipt, System.String transactionID) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.FakeStore.<>n__0 (System.String id, System.String receipt, System.String transactionID) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.FakeStore+<>c__DisplayClass15_0.<FakePurchase>b__0 (System.Boolean allow, UnityEngine.Purchasing.PurchaseFailureReason failureReason) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.FakeStore.FakePurchase (UnityEngine.Purchasing.ProductDefinition product, System.String developerPayload) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.FakeStore.Purchase (System.String productJSON, System.String developerPayload) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.JSONStore.Purchase (UnityEngine.Purchasing.ProductDefinition product, System.String developerPayload) (at <92f676e7e5534a3c8ca20b16bdd43b31>:0)
    UnityEngine.Purchasing.PurchasingManager.InitiatePurchase (UnityEngine.Purchasing.Product product, System.String developerPayload) (at <e647153c046145fb94ba309b1e626b12>:0)
    UnityEngine.Purchasing.PurchasingManager.InitiatePurchase (UnityEngine.Purchasing.Product product) (at <e647153c046145fb94ba309b1e626b12>:0)
    SIS.IAPManager.PurchaseProduct (System.String productId) (at Assets/SimpleIAPSystem/Scripts/IAPManager.cs:376)
    SIS.IAPListener.PurchaseProSubscriptionMonthly () (at Assets/SimpleIAPSystem/Scripts/IAPListener.cs:261)
    

    P.S. Unity 2019.4.1, Android Target



  • I already had this discussion here: https://www.rebound-games.com/forum/post/11180

    What receipt would you like to validate in the editor? No payment, no receipt.



  • @Baroni I just want to receive correct purchase callback in Editor for testing purposes.

    updated:

    When I change server side validation verification type to "On Start" or "On Purchase" From "Both" then I receive correct purchase callback (no errors), but when "On Start" product becomes not purchased on next play.

    1. Why I can't set use "Both" Verification? My game will have both subscription and one-time IAP.
    2. Why product becomes not purchased on next play?


  • You should not switch the validation type back and forth between testing stages. If you do, make sure to fully wipe the local transaction log of Unity IAP (calling UnityPurchasing.ClearTransactionLog somewhere at launch) and also clearing the local database (Window > Simple IAP System > Clear Database).

    Each type has a logic to it.

    • OnStart: saves product receipt (optionally encrypted) on purchase, for checking it on next app launch
    • OnPurchase: checks product receipt on purchase. Does not save the receipt for later use
    • Both: does both.

    If you are having subscriptions in your app you should set it (and leave it) to "Both".

    Why product becomes not purchased on next play?

    Possibly because you've switched the type. OnStart is then looking for a receipt on app launch but can't find it, so it thinks of a fake purchase and sets the product back to unpurchased.

    Why I can't set use "Both" Verification? My game will have both subscription and one-time IAP.

    You can, and should. As described above make sure to have a clean testing state.



  • @Baroni said in Subscription Questions:

    calling UnityPurchasing.ClearTransactionLog somewhere at launch

    I tried to call it once in different places of code in IAPManager (before UnityPurchasing.Initialize() and after) in Editor on Mac OS.

    It doesn't work and causes error:

    DirectoryNotFoundException: Could not find a part of the path '/Users/testx/Library/Application Support/Test Company/Test Game/Unity/UnityPurchasing'.
    System.IO.__Error.WinIOError (System.Int32 errorCode, System.String maybeFullPath) (at <fb001e01371b4adca20013e0ac763896>:0)
    

    Your link says: "This method writes to persistent storage and may throw IO related Exceptions, for example if the device's storage is removed or read-only."

    So I checked Mac OS Settings > Security & Privacy > Privacy, and Unity has access to Documents folder where project is located. I provided full disk access & restarted Unity: no result > It just throws the error. Any thoughts?


    If I use next construction on start then purchase flow has no errors in Editor Testing:

                if (Application.isEditor)
                {
                    Destroy(receiptValidatorServer);
                }
    


  • I really don't know what you are doing. We have multiple customers using server validation for subscriptions, but you are running into issues I've never heard before. I do not get that error neither on MacOS, nor Windows.

    For debugging, I just put a button in the scene that calls UnityPurchasing.ClearTransactionLog at runtime, after Unity IAP is initialized.



  • @Baroni UnityPurchasing.ClearTransactionLog() tries to access to folder which doesn't exist: "/Users/testx/Library/Application Support/Test Company/Test Game/Unity/UnityPurchasing".

    I checked "/Users/testx/Library/Application Support/Test Company/Test Game/Unity". There is no "UnityPurchasing" folder. There is only folder called "fcbe6def-34d4-413a-9981-a45cbd2b03a9" which contains "Editor" & "IAP" folders.


    If it makes sense, I don't build for Mac OS, I just test in Editor (my Target Platform is Android).


    I also tried to update Unity Project from 2019.4.1 to 2019.4.3: same result.
    But interesting thing is that after project updating I saw in console next message:

    "Error: Could not load signature of UnityEngine.Purchasing.UIFakeStore:GetOkayButton due to: Could not load file or assembly 'UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. assembly:UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null type:<unknown type> member:(null) signature:<none>"


    In normal conditions Server Side validation must work in Editor as fake without connection to server, right?



  • Honestly fake testing with Unity IAP does not make any sense at all. In line 35 of ReceiptValidatorServer.cs, change

    #if UNITY_ANDROID || UNITY_IOS || UNITY_TVOS
    

    to

    #if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS || UNITY_TVOS)
    

    and it will not throw the NullReferenceException anymore.



  • Today I've tested subscription on Android 10. There are some issues.


    I have this message on purchasing subscription on Android & on next app launches with Internet access.

    com.test.subscription.monthly verification success.


    Issue 1 — access_token.php stability

    This message will show after that when I manually delete one character on secure string in access_token file. And after this exception I still have access to subscription.

    It's the issue. You need to wrap it in "try catch".
    No matter how acces_token file was changed.

    Uploading Crash Report
    07-12 13:48:50.084  8579  8606 E Unity   : NullReferenceException: Object reference not set to an instance of an object.
    07-12 13:48:50.084  8579  8606 E Unity   :   at SIS.ReceiptValidatorServer+<WaitForRequest>d__5.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 
    07-12 13:48:50.084  8579  8606 E Unity   :   at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0
    

    Next, When I returned deleted character then I have verification success.


    Issue 2 — Subscribe again after max auto-renewing period

    As it said here (https://developer.android.com/google/play/billing/test) In testing environment on Android: Monthly subscription will have 5 minutes billing period & test subscriptions can renew a maximum of 6 times.

    So subscription was verificated good for these 30 min. After that subscription was not verificated as expected. Perfect.

    Then When I clicked to subscribe, I paid with test card normally in native window but console showed next exception & subscription was not activated:

    Uploading Crash Report
    07-12 14:36:02.163 20166 20193 E Unity   : NullReferenceException: Object reference not set to an instance of an object.
    07-12 14:36:02.163 20166 20193 E Unity   :   at SIS.ReceiptValidatorServer+<WaitForRequest>d__5.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 
    07-12 14:36:02.163 20166 20193 E Unity   :   at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0
    

    Next I restarted the app and subscription was verificated normally.


    Issue 3 — Pausing does not work

    Canceling works good, but pausing don't work.
    I still have access to subscription in pause testing period.


Log in to reply