question

tongar-guven avatar image
tongar-guven asked

Apple (iOS) receipt validation in Unity IAP

Hello, I am currently having an issue with validating receipts on iOS platforms. On Google Play, all seems to be working fine.

I was having an issue with processing transactions. The first time I purchased an item it was passing through fine. But for the second time I purchased the same item, it has prompted me "This In-App Purchase has already been bought. It will be restored for free" even though the item is a consumable. It behaves as if I have not consumed or finished the transaction. But I am completing all transactions as documented in Unity Docs "Saving purchases to the cloud". While I was looking for a possible solution, I have realized that I have forgot to install the Apple addon in PlayFab and figured it could be that causing the issue.

After that I have installed the addon with the bundle id & shared secret, now none of the transactions are passing through on iOS. I inspected the log in PlayFab and it seems that the receipt is invalid. I have not found what could be the issue here since all is working fine on Google Play. Could you please provide assistance. Thanks.

Here is the code snippet where I send the receipt data to PlayFab:

public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
    {
        ...


#if UNITY_ANDROID
        var googleReceipt = GooglePurchase.FromJson(args.purchasedProduct.receipt);
        menuManager.playfabManager.AuthService.ValidateGooglePlayReceipt(
           args.purchasedProduct.metadata.isoCurrencyCode,
           (uint)(args.purchasedProduct.metadata.localizedPrice * 100),
           googleReceipt.PayloadData.json,
           googleReceipt.PayloadData.signature,
           args.purchasedProduct
           );
#elif UNITY_IPHONE || UNITY_IOS
        var appleReceipt = ApplePurchase.FromJson(args.purchasedProduct.receipt);
        menuManager.playfabManager.AuthService.ValidateIOSReceipt(
            args.purchasedProduct.metadata.isoCurrencyCode,
            (int)(args.purchasedProduct.metadata.localizedPrice * 100),
            appleReceipt.Payload,
            args.purchasedProduct
            );
#endif
        return PurchaseProcessingResult.Pending;
    }


public class JsonData
    {
        // JSON Fields, ! Case-sensitive


        public string orderId;
        public string packageName;
        public string productId;
        public long purchaseTime;
        public int purchaseState;
        public string purchaseToken;
    }


public class PayloadData
    {
        public JsonData JsonData;


        // JSON Fields, ! Case-sensitive
        public string signature;
        public string json;


        public static PayloadData FromJson(string json)
        {
            var payload = JsonUtility.FromJson<PayloadData>(json);
            payload.JsonData = JsonUtility.FromJson<JsonData>(payload.json);
            return payload;
        }
    }


public class GooglePurchase
    {
        public PayloadData PayloadData;


        // JSON Fields, ! Case-sensitive
        public string Store;
        public string TransactionID;
        public string Payload;


        public static GooglePurchase FromJson(string json)
        {
            var purchase = JsonUtility.FromJson<GooglePurchase>(json);
            purchase.PayloadData = PayloadData.FromJson(purchase.Payload);
            return purchase;
        }
    }


public class ApplePurchase
    {
        // JSON Fields, ! Case-sensitive
        public string Store;
        public string TransactionID;
        public string Payload;


        public static ApplePurchase FromJson(string json)
        {
            var purchase = JsonUtility.FromJson<ApplePurchase>(json);
            return purchase;
        }
    }

FYI. I am calling ConfirmPendingPurchase in the result callbacks of both ValidateGooglePlayPurchase & ValidateIOSReceipt.

This is the Raw Even JSON of the receipt validation:

{
    "EventName": "player_receipt_validation",
    "PaymentProvider": "iTunes Sandbox",
    "PaymentType": "ReceiptValidation",
    "ReceiptContent": "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",
    "Valid": false,
    "Error": "Invalid receipt",
    "EntityId": "F49199EEDADC143C",
    "EventNamespace": "com.playfab",
    "EntityType": "player",
    "Source": "PlayFab",
    "TitleId": "ECA35",
    "EventId": "3e979d6bfedb42fbaf819fb8e971d938",
    "SourceType": "BackEnd",
    "Timestamp": "2021-11-28T16:43:50.9444168Z",
    "History": null,
    "CustomTags": null,
    "Reserved": null,
    "PlayFabEnvironment": {
        "Vertical": "master",
        "Cloud": "main",
        "Application": "mainserver",
        "Commit": "f4e9e95"
    }
}
apisunity3dsdksIn-Game Economy
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

·
Sarah Zhang avatar image
Sarah Zhang answered

You can check the answer of this thread - Validation problems with iTunes receipts - Playfab Community to learn about how to troubleshoot the iOS receipt issues. As the above thread said, the “invalid receipt” error means some part of your receipt data is incorrect. For your case, if you can confirm the receipt you obtained from Apple is correct, you may need to print the original receipt JSON to check if the “receipt content” you sent is the same as the “Payload” of the original receipt JSON returned by Apple.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.