ProcessPurchase called even if purchase was not completed

I am encountering a bug, seemingly in Unity IAP system, where consumable purchases that were cancelled by the user or that failed for other reasons are still sent through and ProcessPurchase gets called anyway at the next startup of the app, allowing for fake purchases to take place.
This, however, happens only for the first purchase after deleting the app data or installing, but the bug happens again each time data is deleted.
Steps for reproducing are below.

I am mostly using the standard Unity IAP implementation (with code) on Android as per the tutorial. Using latest Unity IAP 1.23.3.

I have tried checking the receipts but all cancelled/failed orders show correct receipts, also I have tried on accounts that were not on the testers list to see if it was a problem with test credit cards but still it wasn’t working.
I have also noticed that when OnInitialized gets called no product appears to be on the StoreController, so no pending transactions could be found and marked for deletion, but ProcessPurchase will get called regardless.

Steps for reproducing:

  • Delete app data from phone or reinstall app.
  • Start a purchase and cancel it or leave it in the IAP UI.
  • Close the app.
  • Open the app again. ProcessPurchase is called as if the first purchase was completed.
  • Try again steps 2-4, ProcessPurchase is not called this time.
2 Likes

@Loris2222 Thanks for the report, we are looking into this.

Any update?
I have since switched to codeless as the issue presents itself using IAP Buttons too, but much less often.
With the codeless setup I am not able to reliably reproduce the bug but it still happens and I have not been able to pinpoint the cause.

I just tested it and failed to reproduce it.

Could you provide the device log so we can have a look? You can add some logs to ProcessPurchase, such as:
6108339--664983--upload_2020-7-20_17-21-34.png

I’m seeing the same kind of issue. I’ll try and get some logs for you shortly.

purchased made for id: purchase5000pu
Transaction: gempagelpbplnppnimfbajho.AO-J1OyV5wnFRYzL5FEtvAXo4lOsT9sVHjba9R3rYoRwOmEDjtHIh6szrVLBxuOMn9-DgeFv-59Dkaw-TKBcv8seNeV2-1F2dHz73rRV1aOOlzj3H-YIdsd1widRiEhNxxToTNxoVntg

It also looks like there’s a receipt for the purchase, but I didn’t capture a log for that. I can if you need me to.

1 Like

I have a video I took of the repro steps, I can provide that as well if you need it.

Yes, Please provide the video to us so we can investigate it further. Many thanks.

https://drive.google.com/file/d/1cIuJO0gHg4_NFDKx2wNHCAAf6nVxMJ87/view?usp=sharing

2 Likes

Thank you. I’ll try to repro it.

Have you been able to find out whats happening? I tried downgrading to an earlier version of IAP, but it seems like I’m still experiencing this issue. Other players have reported getting non-consumables for free as well. I will also mention that I’m using Easy Mobile but I’ve looked at the code and it’s just a wrapper for the unity IAP. It looks like receipts do come back for this aborted purchase when you enter the game.

You would need to contact Easy Mobile, they may have added additional logic. Can you show your Debug.Log statements in ProcessPurchase and the corresponding logs? Just seeing a receipt isn’t sufficient to trigger a purchase, the ProcessPurchase callback would need to be explicitly called.

Ok give me a bit, I’ll add those to my logging at get back to you. I’ve looked at easy mobiles code, it really is just a wrapper, there’s no additional logic, they are picking up the same callbacks.

When you test, do you (the user) then get charged for the cancelled purchase?

I’m using my test account, but no I there’s no charge that appears on the google console for a purchase.

Does the popup purchase dialog say “this is a test only, your credit card will not be charged”? Then you cancel from that, yet the next time you launch, you get a ProcessPurchase? Please Debug.Log all the Product and receipt properties sent in ProcessPurchase if so. You might compare to the Sample IAP project here, without Easy Mobile, to confirm https://discussions.unity.com/t/700293

Yes, that’s what happens. I just finished uploading my log check. This is what I got:

So, I added this to my process purchase

  public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
            {
                SaveLoadController.AddToLog(new ErrorMessage()
                {
                    AppVersion = Application.version,
                    Conditon = $"receipt:{ args.purchasedProduct.receipt}, transId: {args.purchasedProduct.transactionID}",
                    LogType = "InAppPurchasing",
                    TimeLogged = DateTime.Now
                });

                Debug.Log("Processing purchase of product: " + args.purchasedProduct.transactionID);

                IAPProduct pd = GetIAPProductById(args.purchasedProduct.definition.id);
..
..
.

This will add to my log. When I check my logs I see two events, one is expected.

This one is good, it’s a non-consumable.

{
                "Conditon" : "receipt:{\"Store\":\"GooglePlay\",\"TransactionID\":\"GPA.3369-6653-0221-11919\",\"Payload\":\"{\\\"json\\\":\\\"{\\\\\\\"orderId\\\\\\\":\\\\\\\"GPA.3369-6653-0221-11919\\\\\\\",\\\\\\\"packageName\\\\\\\":\\\\\\\"com.TwoXNoodles.IdleIndustry\\\\\\\",\\\\\\\"productId\\\\\\\":\\\\\\\"removeadsanddouble\\\\\\\",\\\\\\\"purchaseTime\\\\\\\":1576676135942,\\\\\\\"purchaseState\\\\\\\":0,\\\\\\\"developerPayload\\\\\\\":\\\\\\\"{\\\\\\\\\\\\\\\"developerPayload\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"is_free_trial\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"has_introductory_price_trial\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"is_updated\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"accountId\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\",\\\\\\\"purchaseToken\\\\\\\":\\\\\\\"kjbafaboocliapgkjbiddblc.AO-J1Oys1-FLzaExCwVdDf1laW3Z4JRC2omA4ICWcf7xjJYRR8LgXD4Ji2Vj5XChFLiV-pavAqBh0wsE3cs7-g5F1Fmp6TbAh4O7UrG_hZ1MiGDtJW__r-iUB0hTmSWq2E3xIH_Jq-FLTpXf89MH0ZOEnt8V82DxUQ\\\\\\\"}\\\",\\\"signature\\\":\\\"fmFU1QNXmE+G\\\\\/\\\\\/vkcclYqjf1H1me4h\\\\\/209DAg+pU32lWsbYx9CXRUIi8ctmc9sFBtt3CMYJbohcVIG47z2AdhU5qe8H3kNZwE2X3RZYDOLpIQ\\\\\/78vD3Hqogca63wN\\\\\/gIMU4r1l4EmFQ5fV5YUSXmg5sFhcLbRgOW8l6paFMowV1aa1Oe0x69\\\\\/81W6C5rnyQMfYz2WxyWJRvN6X98iybpDmLHrQx6jCVvEcyZ+bAYRIgEnlrk8H8Nhu98RE2ov2kE\\\\\/n7aHesnXTJkyQBx4tI18qtb7awRkEnaMq2kuhfGCkrdRWhmJvOsn069kvzTVXdrEgiUamXI7HtPIlx1visQMA==\\\",\\\"skuDetails\\\":\\\"{\\\\\\\"skuDetailsToken\\\\\\\":\\\\\\\"AEuhp4LNW-I_1kC94RQ_Ks6LP-2pyxoQ-cOskAyhTGLIDnLJQXMA7e2NCjGUlnhW_gZh\\\\\\\",\\\\\\\"productId\\\\\\\":\\\\\\\"removeadsanddouble\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"inapp\\\\\\\",\\\\\\\"price\\\\\\\":\\\\\\\"$11.99\\\\\\\",\\\\\\\"price_amount_micros\\\\\\\":11990000,\\\\\\\"price_currency_code\\\\\\\":\\\\\\\"USD\\\\\\\",\\\\\\\"title\\\\\\\":\\\\\\\"Remove All Ads and Double Ad Reward (Idle Industry)\\\\\\\",\\\\\\\"description\\\\\\\":\\\\\\\"Remove all ads and double reward\\\\\\\"}\\\",\\\"isPurchaseHistorySupported\\\":true,\\\"isOwned\\\":true}\"}, transId: GPA.3369-6653-0221-11919",
                "StackTrace" : null,
                "LogType" : "InAppPurchasing",
                "TimeLogged" : {
                    "ticks" : 637323050522951160
                },
                "AppVersion" : "493"
            }

This one, is unexpected. This is a consumable.

                "Conditon" : "receipt:{\"Store\":\"GooglePlay\",\"TransactionID\":\"endkflbkjgapjofnnpkmhljb.AO-J1Ox5r3STywnfOLgHb00zyTih1zLmlOztd77_EyzH3-kAPvF5HAGkxbLOoiXGUXDVdktAF75DUZvaBagt6_t4CCUMpNBrcvE8s-CSTgz2_cSb7hoak4AV4u269YnvCUF8NZXkhWdI\",\"Payload\":\"{\\\"json\\\":\\\"{\\\\\\\"productId\\\\\\\":\\\\\\\"purchase200000pu\\\\\\\",\\\\\\\"purchaseToken\\\\\\\":\\\\\\\"endkflbkjgapjofnnpkmhljb.AO-J1Ox5r3STywnfOLgHb00zyTih1zLmlOztd77_EyzH3-kAPvF5HAGkxbLOoiXGUXDVdktAF75DUZvaBagt6_t4CCUMpNBrcvE8s-CSTgz2_cSb7hoak4AV4u269YnvCUF8NZXkhWdI\\\\\\\",\\\\\\\"purchaseTime\\\\\\\":1595337368772,\\\\\\\"developerPayload\\\\\\\":\\\\\\\"{\\\\\\\\\\\\\\\"developerPayload\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"is_free_trial\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"has_introductory_price_trial\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"is_updated\\\\\\\\\\\\\\\":false,\\\\\\\\\\\\\\\"accountId\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\"}\\\",\\\"signature\\\":\\\"aIOaYAdoacnu0RT\\\\\/brJZt1H7vMShYWdaL+OjwelDnwvfCyWXa94IkwntxTLSisymR94YL3pmWH0\\\\\/a7CbSIZTNzb41c\\\\\/DuUWftuIorRB0PntXrwj0RNUl+eZzVP1nSQjkGVplAc0QneAW06d\\\\\/TyD64vcZYOqSqvSsAw\\\\\/frsjBzv952dY6CBymYZQjSburEsBHszxHHCMJQq3hTA5qNE\\\\\/nK\\\\\/4isavHVpDsd6kX13Vn0031HJlwMf6xHFbHSWZe+9yPOamC3iyUiCzjsbcrIFaJ4H8A026Hum2YpKRdKBnWEpn41d9DJKUzA+McHRknHK+AVzAcPhmqMaLQlhu5VgZ3WQ==\\\",\\\"skuDetails\\\":\\\"{\\\\\\\"skuDetailsToken\\\\\\\":\\\\\\\"AEuhp4LAy4i5R7o0CBuk2zkKCjEVaJSa3jpAqCGmV9orIEKsQPJLzr8JSOnPsKIwnDh7\\\\\\\",\\\\\\\"productId\\\\\\\":\\\\\\\"purchase200000pu\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"inapp\\\\\\\",\\\\\\\"price\\\\\\\":\\\\\\\"$119.99\\\\\\\",\\\\\\\"price_amount_micros\\\\\\\":119990000,\\\\\\\"price_currency_code\\\\\\\":\\\\\\\"USD\\\\\\\",\\\\\\\"title\\\\\\\":\\\\\\\"Purchase 200000 Plutonium (Idle Industry)\\\\\\\",\\\\\\\"description\\\\\\\":\\\\\\\"Purchase 200000 Plutonium\\\\\\\"}\\\",\\\"isPurchaseHistorySupported\\\":true,\\\"isOwned\\\":true}\"}, transId: endkflbkjgapjofnnpkmhljb.AO-J1Ox5r3STywnfOLgHb00zyTih1zLmlOztd77_EyzH3-kAPvF5HAGkxbLOoiXGUXDVdktAF75DUZvaBagt6_t4CCUMpNBrcvE8s-CSTgz2_cSb7hoak4AV4u269YnvCUF8NZXkhWdI",
                "StackTrace" : null,
                "LogType" : "InAppPurchasing",
                "TimeLogged" : {
                    "ticks" : 637323050733080990
                },
                "AppVersion" : "493"
            }

Do you really have an IAP for $119 ? Does your credit card get charged if you’re not using a test account?

Uhh yep. I’m seeing other purchases come in. Some people were doing multiple $40 purchases, so I added a higher tier. 4 for 3.

So you’re getting charged even if you press cancel at that prompt? That’s not good, I will be looking into this. Your repro steps are good, it’s the first purchase attempt after an install. I will follow up.