iOS Restore Button Functionality Problems



  • Hello Baroni,

    My iOS game was recently rejected by Apple due to a mandatory Restore button capability that I'm now in the process of creating using your IAPManager.PurchaseProduct("restore") mechanism.

    In my game, when a purchase is made, I save the receipt information inside the ProcessPurchase method and I then use this information when loading levels to confirm whether or not the user has access rights.

    I'm trying to figure out how this restore process works and I'm not finding the code behind the following call:
    extensions.GetExtension<IAppleExtensions>().RestoreTransactions(OnTransactionsRestored);

    I'm not able to debug into this method. Is this Unity's code? Where is this at?

    After this call the next method that gets called is
    HandleSuccessfulPurchase

    I was hoping that the RestoreTransactions process would have fired calls to ProcessPurchase but from what I can see in my test configuration it is not doing this. Is there another method in the restore process that I can use to save the receipt on a restore? I'm debugging on my Mac Air laptop and will be deploying this to my phone to see if the behavior is different.

    Any suggestions?

    Thank you,
    Robert



  • Hey,

    it is correct that Apple requires a restore button to be present. We provide the UIButtonRestore script for this, which enables that button on iOS only. Of course you could also have your own button and let it call IAPManager.PurchaseProduct("restore").

    Yes, the extension code behind this comes from Unity IAP. It is packed directly into the Unity IAP Purchasing DLL.

    The callback is indeed ProcessPurchase with all purchased products. Then, the "restore" product is passed to the IAPListener's HandleSuccessfulPurchase method for finishing off the restore workflow.

    Testing on a non-mobile device like a laptop, in the Unity Editor, does not work since there are no native purchase events. Therefore, nothing can be restored either.



  • Hello Baroni,

    Thanks for the replay. Yes, I've got my own button and I'm calling the IAPManager.PurchaseProduct("restore").

    I'm testing this on my iPhone 7 and I seeing the following behavior using Test Flight.

    Uninstalled prior version and downloaded my new code with the Restore button in place.

    Clicked on "Restore" and the process came back with no prior purchases found.

    Played the game and when it came time to purchase additional levels clicked "Purchase" and Simple IAP recognizes that I had already bought the levels and performs as expected and calls ProcessPurchase. So, the IAP mechanism is detecting that I have already purchase the non-consumable.

    So, it appears in my case that the PurchaseProduct("restore") mechanism is not calling ProcessPurchase as I believe that it should. HandleSuccessfulPurchase does get executed so it's like the callback registration for ProcessPurchase is broken in the restore pipeline. Where is this ProcessPurchase callback registered with Uniy IAP ??

    I'm pretty frustrated with this as this is the last piece of the work I need to get done to release on the Apple Store... whaddaya charge for 30 minutes of desktop share and phone call support?

    Thanks,
    Robert



  • Where is this ProcessPurchase callback registered with Uniy IAP ??

    Please see the official documentation for that - Simple IAP System does not contain native code modifying that behavior.

    https://docs.unity3d.com/Manual/UnityIAPRestoringTransactions.html

    On Apple platforms users must enter their password to retrieve previous transactions so your application must provide users with a button letting them do so. During this process the ProcessPurchase method of your IStoreListener will be invoked for any items the user already owns.

    I do not offer 1-1 / paid support as per our support policy. Testing via TestFlight is also prone to errors when it comes to in-app purchasing. I would recommend deploying the build from Unity to your mobile device, connected to the computer, directly (via XCode).

    Unfortunately I am not able to reproduce the issue in the example scenes or assist further. I understand that you're probably on a set schedule, but you could try to run the sample scenes of Unity IAP and see if the issue happens there too. Since there is no modification in our code, if you keep experiencing an issue with the default Unity IAP restore functionality you would need to file a bug report with Unity.



  • Hello Baroni,

    You were right. I think TestFlight was causing some of the problems. Testing the version straight from Xcode to the device has improved things just a bit.

    I'm getting a strange warning that doesn't make any sense.

    Assets/SimpleIAPSystem/Scripts/ReceiptValidatorClient.cs(57,100): warning CS0436: The type 'AppleTangle' in '/Users/Documents/SpinCell_Unity/Assets/Resources/UnityPurchasing/generated/AppleTangle.cs' conflicts with the imported type 'AppleTangle' in
    'Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in '/Users/Documents/SpinCell_Unity/Assets/Resources/UnityPurchasing/generated/AppleTangle.cs'.

    Is this an issue with Unity IAP out of sync with Simple IAP? I'm using the latest of SIP with Unity IAP 2.1.1 on Unity 2019.4.10 LTS

    Also, I've observed where on initialization it appears that SIAP or UIAP are confirming my Store Items as I have a number of items in my local store that are not yet available on the Apple Store ... example as follows:

    iPhonePlayer(Darlenes-iPhone):56000 Unavailable product sc_levels15_21 -sc_levels15_21

    At the very end... I get the following...
    iPhonePlayer(Darlenes-iPhone):56000 IAPListener reports: HandleSuccessfulPurchase: sc_levels8_14

    Right after that i get the following...

    iPhonePlayer(Darlenes-iPhone):56000 Local Receipt Validation failed for: sc_levels8_14. Exception: System.NullReferenceException: Object reference not set to an instance of an object.
    at SIS.IAPListener.HandleSuccessfulPurchase (System.String id) [0x00000] in <00000000000000000000000000000000>:0
    at SIS.IAPManager.PurchaseVerified (System.String id) [0x00000] in <00000000000000000000000000000000>:0
    at SIS.ReceiptValidatorClient.Validate (UnityEngine.Purchasing.Product p) [0x00000] in <00000000000000000000000000000000>:0
    at SIS.IAPManager.ProcessPurchase (UnityEngine.Purchasing.PurchaseEventArgs e) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.StoreListenerProxy.ProcessPurchase (UnityEngine.Purchasing.PurchaseEventArgs e) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.PurchasingManager.ProcessPurchaseIfNew (UnityEngine.Purchasing.Product product) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.PurchasingManager.OnPurchaseSucceeded (System.String id, System.String receipt, System.String transactionId) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.JSONStore.OnPurchaseSucceeded (System.String id, System.String receipt, System.String transactionID) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.AppleStoreImpl.OnPurchaseSucceeded (System.String id, System.String receipt, System.String transactionId) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.AppleStoreImpl.ProcessMessage (System.String subject, System.String payload, System.String receipt, System.String transactionId) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.AppleStoreImpl+<>c__DisplayClass37_0.<MessageCallback>b__0 () [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Purchasing.Extension.UnityUtil.Update () [0x00000] in <00000000000000000000000000000000>:0 , Object reference not set to an instance of an object.

    Does this make any sense or offer any clues?

    I'm also posting on Unity Forum as well to see if they can help here.

    Thanks,
    Robert



  • Hi,

    The type 'AppleTangle' in '/Users/Documents/SpinCell_Unity/Assets/Resources/UnityPurchasing/generated/AppleTangle.cs' conflicts with the...

    have you tried deleting/regenerating the Tangle files? Not sure what happened there, maybe a meta file mismatch.

    iPhonePlayer(Darlenes-iPhone):56000 Unavailable product sc_levels15_21 -sc_levels15_21

    That's fine. If you added them to the IAP Settings editor in SIS, it will try to get them. Since they are not live, they are not received yet.

    Local Receipt Validation failed for: sc_levels8_14. Exception: System.NullReferenceException: Object reference not set to an instance of an object.
    at SIS.IAPListener.HandleSuccessfulPurchase

    It fails the receipt validation, but it only calls two methods within ReceiptValidatorClient.cs: line 71 and 72. Could you debug which of those fails?



  • Hello,

    Tried regenerating and the tangle issue still exists.

    The code in the receipt validator client
    validator.Validate(products[i].receipt); this piece executes correctly.

    and it's blowing up with this bit of code
    IAPManager.GetInstance().PurchaseVerified(products[i].definition.id);

    I was not aware that initialization called
    HandleSuccessfulPurchase... I've got some code in there that should only execute after a "button" click only purchase was confirmed.

    Thanks,

    Robert



  • Hello Baroni,

    I'm having one hell of a time trying to debug from the MacOs into an iPhone 7 and I'm finding that whole process compared to debugging an Android device through Windows is so much more difficult than it should be. Right now, I can't seem to figure out the right magic phrase to utter that will reliably let me set a break point into the SIP code, however sometimes I can set a breakpoint into my code attached to a scene.

    Any recommendation here? I'm very new to the mac/ios world and I'm not liking this at all.

    Thanks,
    Robert



  • I was not aware that initialization called HandleSuccessfulPurchase... I've got some code in there that should only execute after a "button" click only purchase was confirmed.

    Yeah, that method is called at initialization for restored products as well, in case the user reinstalled the game. The IAPListener should not contain scene-related code, you would use the DBManager methods or subscribe to IAPManager events (purchaseSucceededEvent) to react on purchases happening during runtime instead.

    I'm having one hell of a time trying to debug from the MacOs [...] is so much more difficult than it should be.

    I feel your pain. It's exactly what I'm doing as well - develop, wait 5 minutes for the build, wait 5 minutes for XCode to load, wait 5 minutes for deployment to mobile device. If I want to debug something on an iOS device, basically I put Debug.Logs everywhere so I do not miss anything, to avoid having to wait 15 minutes for another build. Or just walk around in the house during that time. Unfortunately there is no magic for the build process on iOS.



  • Hi Baroni,

    I just pushed another build to TestFlight and the restore process worked perfectly!

    I found that I had some scene related code that should not have been in HandleSuccessfulPurchase and I rearchitected that process. I also updated my Unity IAP services on the Mac as I found an update that I was not aware of. The package manager component was fine but I had and update to apply where the services were concerned. Either one of those two modifications could have resolved the issue.

    Thanks!
    Robert


Log in to reply