In a receipt after a restoreCompletedTransaction (for a non-consumable or an autoreneawable subscription) or after a re-purchase (after an earlier purchase of a non-consumable or autorenewable subscription)
The receiptData returned by IAP, the TransactionID is not found in the Payload, so it is an invalid TransactionID
The above situation causes the server to fail to verify the order (TransactionID package is or not included in Payload), and cannot issue rewards to users
Now it is only possible to prove that the user is making repeated purchases and resuming purchases through the TransactionID not in the Payload
Is there a better and safer way to prove that users are repeating purchases or resuming purchases?
Which server are you referring to, and what error are you receiving? Users can only purchase non-consumables and subscriptions once, regardless of receipt validation. This is enforced by the store API. Also, we are using purchaseToken now instead of transactionID as mentioned in the release notes Unity IAP package 4.12.2 is now available page-2#post-6434240 and Unity IAP package 4.12.2 is now available page-2#post-6506532
My problems are all on iOS devices
Which server are you referring to
Is our own game backend server
what error are you receiving?
After the client with Apple Store have completed the transaction, the received receipt will be handed over to the server for verification, and an error has occurred.TransactionID not in Payload
we are using purchaseToken now instead of transactionID as mentioned in the release notes
please check the photo
Users can only purchase non-consumables and subscriptions once
- user has 2 devices. purchase made on device 1. user taps ‘purchase’ on device 2 rather than ‘restore’ on device 2. Then Apple had a choice - they could say ‘hey you jerk, tap restore not purchase’ or they could say ‘ok, purchased for free’. They chose the later.
- user makes purchase. app crashes or is deleted and reinstalled. App fails to credit user with purchase. user taps ‘purchase’ rather than ‘restore’. See #1 above.
When the above two situations occur, the TransactionID does not appear in the Payload. Our game server think this is an invalid order and not add assets to the user.
Now we want to know if the above two situations will cause the TransactionID to not be in the payload?
How to determine if the user is repeating the purchase
Unity 2019.4.12f1
IAP 2.2.2
Apple requires a Restore button. Sorry I I don’t quite understand your question. It seems you’ve already determined that the transactionID isn’t in the receipt? We have no control over the receipt contents, that’s from Apple. And what photo are you referring to? Your second image shows the transactionID. Reinstalling the app should make no difference, I do this type of testing everyday without problem. If you don’t use your server in the loop, does purchasing work as expected? A user can’t make a second purchase for a non-consumable or subscription, I would not expect a new ID. Apple enforces this.
For users who reinstall the app, we cannot know if the user has purchased non-consumable items. In the app, we will show users non-consumable items. When users try to purchase non-consumable items, the Apple Store will inform the user that they have already purchased non-consumable items. The Apple store will resume the purchase for the user. Like the first purchase, Unity IAP will receive the receipt from the Apple store, but the purchase order information is not included in the receipt for the resumption of purchase. Cause the game server to think this is an invalid order
This post is the same as my current situation, but they were developed by Apple and I used Unity IAP.
https://developer.apple.com/forums/thread/110067
Apple development will have SKPaymentTransactionStateRestored or SKPaymentTransactionStatePurchased to indicate whether the purchase is resumed or repeated purchase
This is my code:
public class MyStoreListener : IStoreListener
{
private static MyStoreListener instance;
private IStoreController controller;
private IExtensionProvider extensions;
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
this.controller = controller;
this.extensions = extensions;
}
public void InitiatePurchase(string productID)
{
controller.InitiatePurchase(productID);
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
// use e.purchasedProduct.receipt to Verify receipt in game server
return PurchaseProcessingResult.Complete;
}
public void RestorePurchase(Action<bool> callBack)
{
// Restore Purchase
var apple = extensions.GetExtension<IAppleExtensions>();
apple.RestoreTransactions(callBack);
}
}