IAP Badger: a unified approach to in-app purchases

To manage the delay, I take a ‘lazy’ approach to displaying the price on screen.

When I create my in app purchase menu, I leave all of the text objects that will display the product price as empty strings.

Then, when the menu is finally displayed on screen, I check at the moment before everything is made visible whether iap.getLoadProductsCatalogue() has returned any values from the app store yet.  If it has, I copy in the localised price.  If it hasn’t, I leave the text blank and fall back on iOS/Android displaying the price when the user clicks ‘purchase’.

An event driven way to do this would be to pass a listener function to iap.loadProducts().  When the listener is triggered, get your function to fill in prices into all the relevant text objects.

In practice, it’s going to be several seconds between calling iap.loadProducts() and getting the results, even over a mobile network.  With this approach, if you call iap.loadProducts() as early in your app execution as possible, by the time the user has seen your splash screen and navigated your menu system, the prices are likely to be ready for you.

There was a typo in one of my earlier posts, by the way - it should have read call loadProducts() to query the app store, then check the pricing information with getLoadProductsCatalogue().

I’ve edited it so it’s correct for future readers.

Has anyone experienced game crashes on ANDROID during products restore?

I use the same code on iOS and on Android.
I am testing on Samsung Galaxy S3…
I get black screen when attempting to restore (not every time, from time to time).

I’ve not come across this before - maybe try a different daily build?

This is very strange.
On Android 4.1.3 Samsung S3 mini game crashes only on first app start just after installation. It does not crash on manual restore (when I press restore button).

On Android 4.3 Samsung S3 it crashes in both cases (first app start and on manual restore).

I will do some more debugging…
I am using the latest Corona stable build.

On iOS everything works well (there is no automatic restore there).

I am testing in Alpha, and will let you know the results…

It might be worth checking your device debug logs with adb logcat to see if any error messages are coming back through the native Corona store/iap libraries.  

Hi all,

I have one strange situation on Android during alpha testing.

So I have 5 non-consumable items:

  • A, B, C, D, E

For testing purposes I bought two items: C and E (which Googled charged! - and I am testing my app!!)

I deleted/uninstalled my app, and deleted cache memory also.

I re-installed it from Google Play.

Now the strange part comes:

  • I am offline.

  • During Restoring purchases items C and E were unlocked!

How is this possible, because cache is gone and I am offline?

I should be online to restore purchases?

I event tried to go to Flight mode, and items were restored successfully :slight_smile:

I tried this over and over, and same thing happens…

I tried to search .txt file on the phone after deleting my app, and was unable to find it (it was deleted during uninstall).

Tnx.

Goran

Here they say that google play caches purchases to allow offline restoring.

http://stackoverflow.com/questions/21277362/android-in-app-purchase-check-buyer-offline

OK.

Tnx.

So basically Google installs some kind of file during app download, and IAP Badger read-outs that file during Products Restore ??

If this is true nothing is wrong with my code… :unsure:  

I don’t think there is anything wrong with your code and I think that g.sciaccitano is right: when you make a purchase, Google Play caches a copy of that transaction on the device.  

I believe that, when you call the restore function, Corona talks to the native Google Play Store API.  If no internet connection is available, those libraries check the cache on the device to see if they can find any record of purchases for that app.  I would guess that, when an internet connection becomes is available, that cache is refreshed / reconciled with other changes for the user on Google Play’s servers.

 Certainly, IAP Badger doesn’t record a copy of any transactions made on the device.

I don’t know if Rob or anyone else knows any better?

Hi guys,

My app is on Google play Store now (in prod).

When testing in alpha I was able to buy some non consumable products…

Now while in prod I get :  Authentication is required. You need to sign into your Google Account  when trying to buy a product.

I never published beta app version, only alpha (if makes any difference).

Tried different gmail accounts, clearing Google play cache memory: NO HELP.

A lot of native developers are struggling with this (forums…).

Is this Google error, or on our side (our code)??

I am using latest stable build Corona Version 2015.2731 (2015.10.5).

Many thanks.

Ivan

Do you get any extra information through adb logcat?

Here is the part of adb logcat (I filtered Corona messages):

D/Finsky  ( 9811): [6297] InAppBillingUtils.getPreferredAccount: com.xxx.xxxx.xxxx: Account determined from library ownership - [blablablabla]

E/Parcel  ( 2357): Class not found when unmarshalling: com.google.android.finsky.billing.lightpurchase.PurchaseParams

E/Parcel  ( 2357): java.lang.ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams

E/Parcel  ( 2357): at java.lang.Class.classForName(Native Method)

E/Parcel  ( 2357): at java.lang.Class.forName(Class.java:204)

E/Parcel  ( 2357): at java.lang.Class.forName(Class.java:169)

E/Parcel  ( 2357): at android.os.Parcel.readParcelableCreator(Parcel.java:2091)

E/Parcel  ( 2357): at android.os.Parcel.readParcelable(Parcel.java:2055)

E/Parcel  ( 2357): at android.os.Parcel.readValue(Parcel.java:1971)

E/Parcel  ( 2357): at android.os.Parcel.readMapInternal(Parcel.java:2255)

E/Parcel  ( 2357): at android.os.Bundle.unparcel(Bundle.java:223)

E/Volley  ( 9811): [6305] BasicNetwork.performRequest: Unexpected response code 403 for https://android.clients.google.com/fdfe/preparePurchase

D/Finsky  ( 9811): [1] PurchaseFragment.onStateChange: Error: PurchaseError{type=2 subtype=0}

D/Finsky  ( 9811): [1] PurchaseFragment.onStateChange: Purchase failed: PurchaseError{type=2 subtype=0}

I/InputReader( 2357): Touch event’s action is 0x0 (deviceType=0) [pCnt=1, s=0.4127] when=13823079326000

I/InputDispatcher( 2357): Delivering touch to: action: 0x0

I/InputReader( 2357): Touch event’s action is 0x1 (deviceType=0) [pCnt=1, s=] when=13823171136000

I/InputDispatcher( 2357): Delivering touch to: action: 0x1

D/SensorService( 2357):   -3.8 4.0 7.6

Testing IAP worked OK during Alpha testing.

I never published app to Beta, I published it directly to production.,

I had some app signing difficulties, but I was able to sign it before it went to production.

https://forums.coronalabs.com/topic/60864-android-keystore-not-valid/

Any ideas?

Thanks.

Ivan

Are you actually able to find your app in Google Play store?  A simple solution to this is that the message that your app has been upgraded to production hasn’t percolated around Google Play’s servers around the world.  That means that, when you try to purchase using your standard (not testing) account, it thinks the app is still in alpha - and so not available to the general public.  If I were you, I’d delete the app from your device, download the app from Google Play and try testing that.

If waiting for a few (tense) hours doesn’t work, I’d look at the signing of your app.  I haven’t got any experience with the native Android SDK but, from the stack trace, I think Google Play is saying that the IAP product identifier you used isn’t registered for your app.  (Of course, you’d also get this if the servers haven’t caught up to the changes in your console as well).

One test would be to use the loadProducts function to grab a catalogue of all the IAP products that Google Play knows are registered for your program.  If the contents of the catalogue are not what you expect, then you know the problem is to do with the signing/identification of your app (because it’s not finding the products you entered into Google Play console).  If loadProducts returns the catalogue you are expecting, there is something else going on here.

When you upload a new version of your app to alpha testing, it is really important that you sign it in exactly the same way, with exactly the same keystore tht you used to sign your production app (and I can see from the post you linked to there were issues with this).  Obviously, you cannot use a debug keystore to sign a production app.

I don’t think it matters about progressing from alpha to beta and then to production, by the way.  I always miss out the beta step.

Hope all that made sense.

Many thanks for a lenghty answer!

  1. My app is on Google Play for 2 days now. I was able to delete and find it on Google Play.

  2. I assume to test loading products I will have to upload a brand new app version with amended code in Alpha or in Production?

  3. To be honest signing part sucks. We do not have any control over it. I mean the same keystore accepts password, then 10 times does not accept it, then you just change folders (move keystore), then it accepts its, then not and etc…
    Who knows if app has been properly signed or not :slight_smile:

I don’t think that there is any kind of test to verify that (servers accepted my app every time)?
And last question: if one of my alpha or production versions has not been signed properly, that means the end for this app, or what should I do?

Hi again,

I think you should be fine to just recompile your code and transfer it to the device via USB - just give it the same version number/code as your production code on Google Play for the time being.  (The alternative is to upload another version to alpha if you want to share it more easily with any testers).

I’m not an expert in signing I’m afraid - I think that once you sign your app with one key, you can’t use a different one in the future.  I’m also sure Google Play will reject any attempt to upload an APK with a different signature.

But if you are having lots of problems already, and no one has really downloaded your app yet, I would be tempted to pull it completely from the store and start over.  (ie. remove the app from Google Play Console, create a brand new version of the app in Google Play Console, create a brand new keystore, and sign and upload your app with that.)  You would at least be able to copy and paste all of the information you’ve already entered into Google Play Console for your app from last time.

(That’s just what I would do.  I’m going to reiterate I’m really not an expert in code signing, but losing a bit of time refreshing your set up might save a lot of time/heartache debugging a difficult app set up in the future…)

Thanks happymongoose, I think I will delete app and create a new one (4 downloads so far  :smiley: ).

No marketing ($$$), no game.

Many thanks once again!

Hi happymongoose,

No luck: still getting “Authentication Error” while trying to buy a non-consumable product.

Problem chronology looks like this:

  1. IAP worked while app was tested  in Alpha.

  2. Promoted my app to  Production.

  3. IAP did not worked (adb report above).

  4. Tried even on other people phones… same error happend to them while app was in  production.

  5. Unpublished my app and renamed it.

 

------------------ NEW APP

  1. Signed new app with completely new keystore (app is published in Alpha).

  2. IAP`s are active in Google Play Console.

8) Same problem again!

 

 

I was wondering, where should I place:

local licensing = require( "licensing" ) licensing.init( "google" )

in main.lua or in chooselevel.lua (all IAP badger functions are in chooselevel.lua)?

Because if I place it in main.lua maybe there is not enough time to accomplish licensing part…

I did not include following in config.lua:

policy = "serverManaged"

But that is apparently an optional line…  :rolleyes:

One last question:

My app is  FREE  with IAP inside.

 

Are following lines required for FREE apps:

 

main.lua

local licensing = require( "licensing" ) licensing.init( "google" )

build.settings

"com.android.vending.CHECK\_LICENSE",

Hi Ivan,

  • I don’t think those licensing ‘require’ statements affect IAP one way or the other.  They’re for checking whether your app has been download from Google Play legally (ie. it hasn’t been hacked and copied).  It is obviously worth checking this, even for a free app, but won’t affect the issue here.
  • You do need your app license key to be included in your config.lua file though (see the project configuration section of this page here).
  • Have you tried running iap.loadProducts in your code to see what registered IAP products come back from Google Play?

Hi happymongoose,

Many thanks for your support!

Promoting app to beta did the trick.

All products were registered on adb logcat… but still.

Don`t know why…

It seems like every platform has its shortcomings, IAP`s and signing are certainly that on Android.

Many thanks once again!

Ivan