IAP Badger - Need help with first implementation

[This text was automatically translated with DeepL (German -> English).]

I’ve been trying to implement in-app purchases into my game for some time now. But no matter which variant I try (without and with IAP Badger plugin), it just won’t work. The big advance was a variant without plugin: I could buy a product and then the app crashed. The product was actually bought, however, because the second call refused to buy (as it had already been bought). Since I’m pretty desperate, I hope you can give me a helpful tip. I use the Corona version 2017.3169 and the app runs over the alpha channel. For testing I use a second Google Account on my smartphone. The variant below is the attempt with the plugin to make the whole thing work. But as you can see from the debug output, it doesn’t work. What am I doing wrong?

build.settings

settings = {     ...     android =     {         usesPermissions =         {             "android.permission.INTERNET",             "com.android.vending.BILLING"         },     },     plugins =     {         ["plugin.google.iap.v3"] =         {             publisherId = "com.coronalabs",             supportedPlatforms = { android = true },         },         ["plugin.iap\_badger"] =         {             publisherId = "uk.co.happymongoose",         },     },    ... }

config.lua

application = {     content =     {         width = 320,         height = 480,         scale = "letterbox",         fps = 60,     },     license =     {         google =         {             key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",         },     }, }

main.lua

local iap = require("plugin.iap\_badger") iap.init( {     catalogue = {         products = {                  testproduct1 = {                 productNames = {                     apple="xxxxxxxxxxxxxxxxxx.purchase.testproduct1",                     google="xxxxxxxxxxxxxxxxxx.purchase.testproduct1",                     amazon="xxxxxxxxxxxxxxxxxx.purchase.testproduct1"                 },                 productType = "non-consumable"             },             testproduct2 = {                 productNames = {                     apple="xxxxxxxxxxxxxxxxxx.purchase.testproduct2",                     google="xxxxxxxxxxxxxxxxxx.purchase.testproduct2",                     amazon="xxxxxxxxxxxxxxxxxx.purchase.testproduct2",                 },                 productType = "consumable"             }         }     },     --debugMode = true } ) local function purchaseListener( product )     print "Purchase made"     print( product )     if product == "testproduct1" then         iap.purchase( "testproduct2", purchaseListener )     end end iap.purchase( "testproduct1", purchaseListener )

console

11-07 16:45:03.536&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \> Class.forName: network.LuaLoader 11-07 16:45:03.536&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \< Class.forName: network.LuaLoader 11-07 16:45:03.537&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : Loading via reflection: network.LuaLoader 11-07 16:45:03.546&nbsp; 8448&nbsp; 8463 I Corona&nbsp; : Platform: Moto G (5) Plus / ARM Neon / 7.0 / Adreno (TM) 506 / OpenGL ES 3.2 V@145.0 (GIT@Id9e7eae3da) / 2017.3169 / Deutsch | DE | de\_DE | de 11-07 16:45:03.559&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \> Class.forName: shared.google.play.services.base.LuaLoader 11-07 16:45:03.566&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \> Class.forName: CoronaProvider.licensing.google.LuaLoader 11-07 16:45:03.566&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \< Class.forName: CoronaProvider.licensing.google.LuaLoader 11-07 16:45:03.567&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : Loading via reflection: CoronaProvider.licensing.google.LuaLoader 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; : Invalid public key 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; : java.lang.IllegalArgumentException: com.google.android.vending.licensing.util.Base64DecoderException: Bad Base64 input character at 21: 45(decimal) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:118) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.LicenseChecker.\<init\>(LicenseChecker.java:92) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at CoronaProvider.licensing.google.LuaLoader.initLicenseChecker(LuaLoader.java:174) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at CoronaProvider.licensing.google.LuaLoader.init(LuaLoader.java:144) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at CoronaProvider.licensing.google.LuaLoader$InitWrapper.invoke(LuaLoader.java:421) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.JavaToNativeShim.nativeResize(Native Method) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.JavaToNativeShim.resize(JavaToNativeShim.java:381) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.CoronaGLSurfaceView$CoronaRenderer.onSurfaceChanged(CoronaGLSurfaceView.java:378) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1612) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1378) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; : Caused by: com.google.android.vending.licensing.util.Base64DecoderException: Bad Base64 input character at 21: 45(decimal) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.util.Base64.decode(Base64.java:546) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.util.Base64.decode(Base64.java:474) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.util.Base64.decode(Base64.java:420) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.google.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:109) 11-07 16:45:03.594&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... 9 more 11-07 16:45:03.595&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \> Class.forName: \_CoronaSetup.LuaLoader 11-07 16:45:03.599&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \> Class.forName: plugin.google.iap.v3.LuaLoader 11-07 16:45:03.600&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : \< Class.forName: plugin.google.iap.v3.LuaLoader 11-07 16:45:03.600&nbsp; 8448&nbsp; 8463 V Corona&nbsp; : Loading via reflection: plugin.google.iap.v3.LuaLoader 11-07 16:45:04.732&nbsp; 8448&nbsp; 8463 W Corona&nbsp; : InitRuntimeTask: thread id: 13269 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; : StoreTransactionRuntimeTask: dispatching Google IAP storeTransaction event 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; : com.naef.jnlua.LuaRuntimeException: ?:0: attempt to concatenate field 'productIdentifier' (a nil value) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.naef.jnlua.LuaState.lua\_pcall(Native Method) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.naef.jnlua.LuaState.call(Unknown Source) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.CoronaLua.dispatchEvent(CoronaLua.java:138) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at plugin.google.iap.v3.StoreTransactionRuntimeTask.executeUsing(StoreTransactionRuntimeTask.java:117) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.CoronaRuntimeTaskDispatcher$TaskEvent.Send(CoronaRuntimeTaskDispatcher.java:170) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.events.EventManager.sendEvents(EventManager.java:91) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.Controller.updateRuntimeState(Controller.java:308) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.CoronaGLSurfaceView$CoronaRenderer.onDrawFrame(CoronaGLSurfaceView.java:421) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1623) 11-07 16:45:04.808&nbsp; 8448&nbsp; 8463 E Corona&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1378)

Is my code always correct? I’m trying to narrow down the mistake. Unfortunately, I don’t know if the problem is in my code, the plugin or the Play Store configuration. I am very grateful for every tip.

11-07 16:45:03.594  8448  8463 E Corona  : Invalid public key
11-07 16:45:03.594  8448  8463 E Corona  : java.lang.IllegalArgumentException: com.google.android.vending.licensing.util.Base64DecoderException: Bad Base64 input character at 21: 45(decimal)

Hallo,

The debug message indicates that the google license key is wrong. Did you copy/paste it correctly from the play console?

Also, I think your purchase transaction listener implementation is flawed. When you initiate purchase, you need need to listen to the event.name and event.transaction.state returned. You also need to do store.finishTransaction before you initiate a second transaction. I mean, you shouldn’t initiate a second purchase from inside the listener. Do first purchase; listen to the results; finish transaction; then initiate second purchase. 

If the above code is just an example, then please post the exact code so we could help.

also, the corona documentation regarding iap are very detailed and well documented and have good examples. I believe they could help you better. here is the link

Luay

EDIT: if someone else thinks we could issue a second purchase before doing store.finishTransaction for the first then please correct me.

@luaykanaan: Thanks for your advice. I used the wrong license key. Now it works. :)))
To your second post: My code works. The IAP Badger plugin works differently than the pure Corona solution.

@webpsm: I’m glad I could help. Happy coding…