RuntimeException after purchase(but ok for restore) on Androids

Hey guys,

what to do, how to fix it?

I checked license key - it is ok. Restoring works fine.

I have this error on android after successful purchase:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=3, result=-1, data=Intent { (has extras) }} to activity {com.elitegamesltd.royalquest/com.ansca.corona.CoronaActivity}: java.lang.IllegalArgumentException: plugin.google.iap.v3.util.Base64DecoderException: single trailing character at offset 640 at android.app.ActivityThread.deliverResults(ActivityThread.java:4221) at android.app.ActivityThread.handleSendResult(ActivityThread.java:4264) at android.app.ActivityThread.-wrap20(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1613) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:163) at android.app.ActivityThread.main(ActivityThread.java:6383) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) Caused by: java.lang.IllegalArgumentException: plugin.google.iap.v3.util.Base64DecoderException: single trailing character at offset 640 at plugin.google.iap.v3.util.Security.generatePublicKey(Security.java:112) at plugin.google.iap.v3.util.Security.verifyPurchase(Security.java:89) at plugin.google.iap.v3.util.IabHelper.handleActivityResult(IabHelper.java:500) at plugin.google.iap.v3.LuaLoader$5.onHandleActivityResult(LuaLoader.java:327) at com.ansca.corona.CoronaActivity.onActivityResult(CoronaActivity.java:3406) at android.app.Activity.dispatchActivityResult(Activity.java:7125) at android.app.ActivityThread.deliverResults(ActivityThread.java:4217) ... 9 more Caused by: plugin.google.iap.v3.util.Base64DecoderException: single trailing character at offset 640 at plugin.google.iap.v3.util.Base64.decode(Base64.java:559) at plugin.google.iap.v3.util.Base64.decode(Base64.java:474) at plugin.google.iap.v3.util.Base64.decode(Base64.java:420) at plugin.google.iap.v3.util.Security.generatePublicKey(Security.java:102) ... 15 more

Any ideas what I’m doing wrong?

(same code works fine for my other project).

store = require("plugin.google.iap.v3"); function storeInitHandler(event) local transaction = event.transaction; if (transaction.state == "purchased" or transaction.state == "restored") then local buy\_id = transaction.productIdentifier; buyHandlerCall(buy\_id); end end store.init(storeInitHandler); store.purchase(buy\_id);

In Googling the error, it seems that people get that a lot with a bad public key. It’s just I don’t know where you specify a public key other than your keystore so that doesn’t seem to be quite right either. Clearly the error is that a base64 string is a character short, or a character long. 

I’ll ask engineering but this is the first time this has come up so it sounds like a problem in a setup somewhere.

Rob

I have found a weird thing: it works without a crash - if items are consumable.

so if I do NOT call store.consumePurchase - it gives this error.

If I call it - it is working fine.

Maybe I’m doing something wrong and corona was updated?

Google changed their IAP’s a while back. There is no longer a difference between Managed (non-consumable) and Unmanaged (consumable) items. You basically have to call store.consumePurchase() on everything.

Rob

No, it is not =) (if the item is not consumable - you should not call consume after buying it).

If an item should be available for purchase again - then you call consume after purchase. Otherways google API will return ‘owned’. And currently, it behaving like that. If after the crash - I`ll try to buy again the same item - there will be no error, and the user will get his item without a problem.

Let me re-phrase that. You have to call consumePurchase() if you intend to allow the user to purchase it a second time. There is no difference to Google. They expect you to maintain that:

https://developer.android.com/google/play/billing/api

There is no distinction in the Google Play Developer console between a consumable vs. non-consumable. They are all considered “Managed products”. 

If you call store.purchase() on an item that has already been purchased, it should not work until you call store.consumePurchase(). It’s up to you to track if it’s a one-time purchase or a multi-purchase and call store.consumePurchase() when the item is consumed. Your description above makes it sound like this is what’s happening.

You’re describing calling store.purchase() after calling store.consumePurchase() as working vs. calling store.purcahse() without previously calling store.consumePurchase() crashing. If you hadn’t previously successfully called store.purchase() there wouldn’t be a reason to call store.consumePurchase() which leads me to believe that you are successfully calling store.purchase() at least once on the items in question which would lead you to the situation you’re describing.

Rob

No.

Here is my case:

  1. I uploaded APK to google store with IAPs.

I tried to buy them - but APK crashed(error in first post).

Simple code - store.purchase() and nothing more.

  1. Posted here on forum my problem.

  2. I checked my other games - and they were working fine. This is my first game with a non-consumable IAPs - so I decided to consume them and see if APK would fail. It did not. In order to do that: I refunded my purchases, added store.consumePurchase(), and tested.

I dont call store.consumePurchase() before store.purchase().

I have this problem from Sunday - so I had some time to experiment with it - in order to give you more info.

Sorry for my english =)

When I wrote

No, it is not =)

I meant - what you wrote afterward - store.consumePurchase()  for consumable items, and not calling that method makes them non-consumable.

Same error with IAP (restore). Please help me!

I think this is a problem from Corona plugin. Previous projects I used similar methods to work well

dce1217f58d407f525e7d27b55717d5b.png

In Googling the error, it seems that people get that a lot with a bad public key. It’s just I don’t know where you specify a public key other than your keystore so that doesn’t seem to be quite right either. Clearly the error is that a base64 string is a character short, or a character long. 

I’ll ask engineering but this is the first time this has come up so it sounds like a problem in a setup somewhere.

Rob

I have found a weird thing: it works without a crash - if items are consumable.

so if I do NOT call store.consumePurchase - it gives this error.

If I call it - it is working fine.

Maybe I’m doing something wrong and corona was updated?

Google changed their IAP’s a while back. There is no longer a difference between Managed (non-consumable) and Unmanaged (consumable) items. You basically have to call store.consumePurchase() on everything.

Rob

No, it is not =) (if the item is not consumable - you should not call consume after buying it).

If an item should be available for purchase again - then you call consume after purchase. Otherways google API will return ‘owned’. And currently, it behaving like that. If after the crash - I`ll try to buy again the same item - there will be no error, and the user will get his item without a problem.

Let me re-phrase that. You have to call consumePurchase() if you intend to allow the user to purchase it a second time. There is no difference to Google. They expect you to maintain that:

https://developer.android.com/google/play/billing/api

There is no distinction in the Google Play Developer console between a consumable vs. non-consumable. They are all considered “Managed products”. 

If you call store.purchase() on an item that has already been purchased, it should not work until you call store.consumePurchase(). It’s up to you to track if it’s a one-time purchase or a multi-purchase and call store.consumePurchase() when the item is consumed. Your description above makes it sound like this is what’s happening.

You’re describing calling store.purchase() after calling store.consumePurchase() as working vs. calling store.purcahse() without previously calling store.consumePurchase() crashing. If you hadn’t previously successfully called store.purchase() there wouldn’t be a reason to call store.consumePurchase() which leads me to believe that you are successfully calling store.purchase() at least once on the items in question which would lead you to the situation you’re describing.

Rob

No.

Here is my case:

  1. I uploaded APK to google store with IAPs.

I tried to buy them - but APK crashed(error in first post).

Simple code - store.purchase() and nothing more.

  1. Posted here on forum my problem.

  2. I checked my other games - and they were working fine. This is my first game with a non-consumable IAPs - so I decided to consume them and see if APK would fail. It did not. In order to do that: I refunded my purchases, added store.consumePurchase(), and tested.

I dont call store.consumePurchase() before store.purchase().

I have this problem from Sunday - so I had some time to experiment with it - in order to give you more info.

Sorry for my english =)

When I wrote

No, it is not =)

I meant - what you wrote afterward - store.consumePurchase()  for consumable items, and not calling that method makes them non-consumable.

Same error with IAP (restore). Please help me!

I think this is a problem from Corona plugin. Previous projects I used similar methods to work well

dce1217f58d407f525e7d27b55717d5b.png