[SOLVED] How implement In-App Purchase?

Previous topic - Next topic

msx

After failing my attempt to implement Admob Interstitial, I am obliged to find a new business model for my application. I think I finally will try to use IAP. In this thread, MrPlow and spacefractal tried to help me, however I still have some doubts.

- Is there a practical manual on the forum or a summary of the steps to follow?. I get lost with so much code.

- Can I do tests without having to upload the application to Play store?

MrPlow

Hi

The problem is also there are a few versions. I am working on adding / reenabling iaps for one of my apps now too so not even sure if it still works for mine. Its been a while since I implemented my IAP but I will try to recall the steps:

1. first you need to see what version of AE and GLB you are working with and get the right ones.
2. Check that all files are in your projected and included
3. Get your long developer ID code from Playstore IAP section on console in put iap_config
4. Add your manifest entries for permission for billing
5. Add your IAP product to your app in play console.
6. Upload and test

I think you should probably build a little test apk separate to your app and use that to test in-app features.

I think I might do that myself, If I do I will share with you. But I am working on client project at the moment.








Comp:
Speccy-48k, Speccy-128k, Amigas, PCs

msx

Thanks Mr.Plow, that would be helpful for me. In any case I will try to work with this information.

msx

#3
I respond to each point in red

1. first you need to see what version of AE and GLB you are working with and get the right ones.

this is the version that I use and I think it is the last:

// Project: Project Glbasic StoreKit
// Start: Sunday, September 08, 2013
// IDE Version: 11.414


2. Check that all files are in your projected and included

Actually in my project are:

inapp_config.gbas, inapp_functions.gbas, AndroidExtras.gbas, Func_General.gbas and hushnumber.gbas


3. Get your long developer ID code from Playstore IAP section on console in put iap_config

I think it's something like:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAij9ylltNxktl3lLV2ClBvueZ5hA4Iq7j73KClCBIMW1YZam+2XkQahANmNiTUDEQwPUaH2Rf+qWJxXydDTRCG0uv/DjHtJxCJ18sO+WuS7PWfle8RCyTCIXLsuBCT3YArEnC32jAiMqUA40zllVcJbPAgRU+U......./Y0g8EY+NLRxlMtiRvIVsrz4Hv6Gz5p9a+41oLSf3GouGttQ3IOvPJeuGt2ZOhU2z1fX14cCtI3LGqKJrTWv99tha5g033cO7Id+VOurenRVyYVcHXZwz1yDnuvJlmuNvKKCrOlmmL2YGFrbJfsXIvb7fm+GQF+79CGdywIDAQAB


4. Add your manifest entries for permission for billing

I have added

   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.WAKE_LOCK" />
   <uses-permission android:name="android.permission.BLUETOOTH" />
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
   <uses-permission android:name="com.android.vending.BILLING"/>


5. Add your IAP product to your app in play console.

I added this product

com.mycompany.test.purchase


6. Upload and test

I uploaded this code for test the inapp.
Code (glbasic) Select

// --------------------------------- //
// Project: test
// Start: Friday, July 22, 2016
// IDE Version: 14.001


// SETCURRENTDIR("Media") // go to media files
SYSTEMPOINTER TRUE

LOCAL mx, my, b1, b2

WHILE 1

PRINT "Store ONLINE: "+InAppPurchase_isOnline(),0,0

PRINT "Precio: "+InAppPurchase_Price$("com.mycompany.test.purchase"),0,20

PRINT "Se compró ya?: "+InAppPurchase_isAvailable("com.mycompany.test.purchase"),0,40

PRINT "Estado de la compra: "+InAppPurchase_Activate("com.mycompany.test.purchase"),0,60

InAppPurchase_Update()

SHOWSCREEN

MOUSESTATE mx, my, b1, b2

IF b1 THEN END

WEND


I attach a PNG with the result.

Is there something I was doing wrong?

spacefractal

#4
The various versions is due Google require updates. v2 is depreacted long time ago, which the old StoreKit was used.

Howover use this one im used for Greedy Mouse (which is a mix of old shop and new shop, where config was integrated with the code, which its should not do that for easier update).

here is something you can use with your SKU:
Code (glbasic) Select

That storekit is too old today, sadly. Im afreid. That version seens using the old version, which is not supported anymore (due Google required a update to v3).

For issues and what its happens is MUCH easier, when you looking into your LOGCAT, which is important when doing stuff like this.

The storekit version im have and using with current Greedy Mouse is like this:

[code=glbasic]
// --------------------------------- //
// Project: GreedyMouse// Start: Thursday, June 27, 2013
// IDE Version: 11.414


// SETCURRENTDIR("Media") // go to media files

GLOBAL INAPP_ERROR$=""      // When a error in a purchase or when restoring.
GLOBAL INAPP_ISONLINE=0     // is network on?
GLOBAL INAPP_PURCHASE$=""   // when a purchase just have been succed.
GLOBAL INAPP_ACTIVATE$=""   // a user is doing the order progress (chould should "progress" to user, if INAPP_ACTIVATE have any content).
GLOBAL INAPP_STATUS$=""     // wating for a callback for either retore or purchase (this can been used when pause was activated).

// **************************** CONFIGURATIONS START HERE ****************************
GLOBAL INAPP_NR_OF_ITEMS=3; // numbers of inapp items you want to uses (this is due init to Android). Not needed for iOS.

// InAppConfig_SkuNames$ configuration for various Appstores. In the game, you might want to only
// use one SKU, which is why its need to been find and convert the ID to the correct name
// for the shop. Also ID numbers is also required for init ITEMS for Android.
//
// For iOS, you also need configuere the Sku Names in the MKStoreKitConfigs.plist too. That
// can been done using xCode. They should named the same with the SKU you configuried in the
// iTunes Connect and similar interfaces.
//
// This can take some time to setup that one.
//
// SKUS should not confict each other on Android stores, or OpenIAP might fails to fid the correct sku, that even on OUYA.
FUNCTION InAppConfig_Sku2Names$: iID$, store$
// check name for "The Premium Key"

IF iID$="0" OR iID$="fullretail"
IF store$="com.ouya.shop"      THEN RETURN ""
IF store$="gamestick.tv.shop"  THEN RETURN "" // SKU is named URL in GameStick Portal
IF store$="com.google.play"    THEN RETURN "com.crislosangames.test.purchase"
IF store$="general" OR store$="android" THEN RETURN "shopkey" // the shared name for this sku for Android Stores (should not conflict allready used)
IF store$="microsoft.windows"  THEN RETURN "windows.fullretail"
iID$="fullretail"
ENDIF
RETURN iID$
ENDFUNCTION


// The Public key from YOUR APPLICATION'S PUBLIC KEY, you get from the Dev Console for that store.
// those Security keys os fpr Android only and is not needed for iOS.
FUNCTION InAppConfig_PublicKeys$: store$
INAPP_DEVKEY = HashNumber("Dffg-rr234-sfgg-34fg-sfsd-hdg-sa234") // just put a totally random sucure key for the hash number (this using for other systems as well).
IF store$="com.google.play" OR store$=1 THEN RETURN "PUT THERE YOUR APPLICATION PUBLIC KEY"
IF store$="microsoft.windows" THEN RETURN HashNumber(InAppConfig_PublicKeys$("com.google.play"))
ENDFUNCTION



// **************************** CONFIGURATIONS ENDS HERE ****************************
//
//
//
//
//
// **************************** INAPP SHOP FUNCTIONS START HERE ****************************
?IFDEF IPHONE
// IMPORT "C" int StoreIsOnline(int) // parents check if the inapp is disabled (0=init once, 1=reinit again).
// IMPORT "C" int StoreIsFeaturePurchased(const char*, int) // checks if the feature have been purchased
// IMPORT "C" int StoreRestored() // is store have been complete (1) or failed (-1)?
// IMPORT "C" void StoreRestore() // Restore any previous purchased items (required on iOS).
// IMPORT "C" int StoreActivate(const char*) // User have just pressed on the buys button in your app.
// IMPORT "C" const char* StoreGetPrice(const char*) // Get a Price for the product.
// IMPORT "C" int StoreActivated() // check the purchasing item....
?ENDIF

GLOBAL INAPP_INIT=0
GLOBAL INAPP_ERROR_TIMER=0  // time before error message vanish.
GLOBAL INAPP_STORE$=""      // the store name going to been used.
GLOBAL INAPP_DEVKEY = 0     // a dev key
GLOBAL INAPP_PURCHASES$=""  // a recent purchase, but waiting for receipt (ANDROID ONLY)
GLOBAL INAPP_RECEPTOK = 0   // Have recept to been checked (ANDROID ONLY)
GLOBAL INAPP_PAUSE = 0
GLOBAL INAPP_SAMSUNGID$     // Group ID for Samsung Apps, is init automatic in the init, based on publickey.
GLOBAL INAPP_INACTIVATESTARTED=0


//
// is the store online?
FUNCTION InAppPurchase_isOnline:
?IFDEF WIN32
InAppConfig_PublicKeys$("nothing")
RETURN 0
?ENDIF

?IFDEF IPHONE
LOCAL ok //=StoreIsOnline(0)
RETURN ok
?ENDIF

?IFDEF ANDROID
LOCAL ok=JavaCall$("Shop:IsOnline")
RETURN ok;
?ENDIF
ENDFUNCTION

// get a price of the current product
FUNCTION InAppPurchase_Price$: iID$
STATIC IDDD$
STATIC IDPRICE$
STATIC counter=0


iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)

?IFDEF WIN32
RETURN "some price"
?ENDIF

?IFDEF IPHONE
// IF IDDD$=iID$ AND IDPRICE$<>"unknown" THEN RETURN IDPRICE$
// LOCAL price$=StoreGetPrice(iID$)
// price$=TRIM$(price$)
// IDDD$=iID$
// IDPRICE$=price$
// RETURN price$
?ENDIF

?IFDEF ANDROID
IF IDDD$=iID$ AND IDPRICE$<>"unknown" THEN RETURN IDPRICE$
LOCAL price$=JavaCall$("Shop:GetPrice:"+iID$)
IF price$="-1" THEN price$="offline"
IDPRICE$=price$
RETURN price$
?ENDIF
ENDFUNCTION

// is the inapp item available? Etc have you brought the item (1) or not (0)? (consumable is not supported yet)
// for some secure reasons, true and false is easy to been hacked, then its uses some hash to get a bit harder to crach.
//
// to also prevent tapping source for exeample from java, checkout fake products and make sure is returned false, which
// give a constant hash number for that. This could been done in various places in your app.
FUNCTION InAppPurchase_isAvailable: iID$
LOCAL orig$=iID$
LOCAL ok%=0

IF INAPP_DEVKEY=0 THEN InAppConfig_PublicKeys$("")
IF INAPP_DEVKEY=0 THEN RETURN 0
orig$=InAppConfig_Sku2Names$(iID$, "android")
iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)

?IFDEF WIN32
ok=INAPP_DEVKEY //StoreWin(iID$, INAPP_DEVKEY)
?ENDIF

?IFDEF IPHONE
//ok=StoreIsFeaturePurchased(iID$, INAPP_DEVKEY)
?ENDIF

?IFDEF ANDROID
ok=JavaCall$("Shop:isAvailable:"+iID$+":"+INAPP_DEVKEY)
?ENDIF

ok=HashNumberBig(ok)
ok=ok-ABS(HashNumberBig(InAppConfig_PublicKeys$("microsoft.windows")))
ok=ok*HashNumber(-ok)
ok=ASL(ok, 4)
ok=ok*HashNumber(orig$)
ok=ok-HashNumber(INAPP_DEVKEY)
ok=ABS(ok)
RETURN ok
ENDFUNCTION

?IFDEF WIN32
FUNCTION StoreWin: iID$, keys
IF INAPP_DEVKEY=0 THEN InAppConfig_PublicKeys$("nothing")
IF INAPP_DEVKEY=0 THEN RETURN 0
LOCAL ok=0

IF iID$="jdg445Ffk439Ffkdd3t" THEN RETURN 0
RETURN keys // allwys return a success.
RETURN 0 // allways return a fail.
ENDFUNCTION
?ENDIF

// Start the payment progress (etc you have pressed on a purchase button).
// On windows, the purchase is allways succes. On iOS and Android, a
// GLB_ON_PAUSE/() can been called here, so you might checks INAPP_STATUS$ for
// eventuelly checks if there us a purchase ongoing or not in there.
FUNCTION InAppPurchase_Activate: iID$
INAPP_INACTIVATESTARTED=1
IF INAPP_STATUS$<>"" AND INAPP_STATUS$<>"Activate"
INAPP_ERROR$="store progress ongoing"
RETURN
ENDIF

iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)
?IFDEF WIN32
InAppPurchase_Finished(iID$)
RETURN TRUE
?ENDIF

?IFDEF IPHONE
// LOCAL ok=StoreActivated() // if user have cancelled purchasem but purcahse did got succes, then the purchase should been activated
// IF ok=1
// INAPP_PURCHASE$=iID$
// INAPP_STATUS$=""
// RETURN
// ENDIF
// StoreActivate(iID$)
// INAPP_STATUS$="Activate"
// INAPP_ACTIVATE$=iID$
// RETURN TRUE
?ENDIF

?IFDEF ANDROID
IF INAPP_STATUS$=""
DEPRINT("InAppPurchase_Activate:"+iID$)
JavaCall$("Shop:Activate:"+iID$)
INAPP_STATUS$="Activate"
INAPP_ACTIVATE$=iID$
ENDIF
?ENDIF
ENDFUNCTION

// A Purchase have just been activated and then its should been saved here locally.
// Only required for Windows for Fake purchases to save the purchases. Its doing
// automatic on Android as well iOS.
FUNCTION InAppPurchase_Finished: iID$
INAPP_PURCHASE$=iID$
IF INAPP_ERROR$="" THEN INAPP_ERROR$="success"
iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)
?IFDEF Win32
SetStr(InAppHelper_HashID$(iID$), "Purchase", 1)
?ENDIF
ENDFUNCTION

// you must do a restore feature for IOS to keep Apple happy to recover all
// perlament purchased items. Dont forget to check the features is Available
// trought InAppPurchase_isAvailable(), which is not automatic done.
//
// a succes would sent a INAPP_PURCHASE$="restored". If user failed to restore
// then a error would been sent to INAPP_ERROR$
//
// This is done automatic on Android and OUYA on startup, but this is required
// for iOS.
FUNCTION InAppPurchase_Restore:
IF INAPP_STATUS$<>"" THEN RETURN

?IFDEF WIN32
FOR i=0 TO 100
LOCAL iID$=InAppConfig_Sku2Names$(i, INAPP_STORE$)
IF iID$<>""
InAppPurchase_Activate(iID$)
ELSE
RETURN
ENDIF
NEXT
?ENDIF

?IFDEF IPHONE
// StoreRestore()
// INAPP_STATUS$="Restore"
// INAPP_ERROR_TIMER=0
?ENDIF
ENDFUNCTION

// This is a updater function, which is required to been invoked in loop time.
// This function checkout ongoing purchases using callbacks. that why you need
// this around a SHOWSCREEN.
FUNCTION InAppPurchase_Update:
LOCAL ok=0
?IFDEF ANDROID
IF INAPP_RECEPTOK=1
INAPP_RECEPTOK=2
INAPP_ERROR$=""
ENDIF
?ENDIF

IF INAPP_ERROR$<>""
INAPP_ERROR_TIMER=INAPP_ERROR_TIMER+UpdateTicks
IF INAPP_ERROR_TIMER>60
INAPP_ERROR_TIMER=0
INAPP_ERROR$=""
ENDIF
ENDIF

?IFDEF WIN32
IF INAPP_INIT=0
INAPP_INIT=1
INAPP_STORE$="microsoft.windows"
InAppConfig_PublicKeys$("")
INAPP_PURCHASE$="restored"
INAPP_RECEPTOK=2
ENDIF
?ENDIF

?IFDEF IPHONE
// IF INAPP_INIT=0
// INAPP_INIT=1
// INAPP_STORE$="apple.appstore.ios"
// INAPP_ISONLINE=StoreIsOnline(0)
// IF INAPP_ISONLINE<>0
// IF INAPP_RECEPTOK<1
// INAPP_PURCHASE$="restored"
// INAPP_RECEPTOK=1
// ENDIF
// ENDIF
// ENDIF

// IF INAPP_STATUS$="Activate"
// INAPP_ERROR_TIMER=0
// ok=StoreActivated()
// IF ok=1
// INAPP_PURCHASE$=INAPP_ACTIVATE$
// INAPP_STATUS$=""
// INAPP_ACTIVATE$=""
// ELSEIF ok=-1 OR (InAppPurchase_isOnline()=0)
// INAPP_STATUS$=""
// INAPP_ACTIVATE$=""
// INAPP_ERROR$="cancelled or failed"
// INAPP_ERROR_TIMER=0
// ENDIF
// ENDIF

// IF INAPP_STATUS$="Restore"
// ok=StoreRestored()
// IF ok=1
// INAPP_RECEPTOK=2
// INAPP_PURCHASE$="restored"
// INAPP_STATUS$=""
// ELSEIF ok=-1
// INAPP_ERROR$="failed"
// INAPP_STATUS$=""
// INAPP_ERROR_TIMER=0
// ENDIF
// ENDIF
?ENDIF

?IFDEF ANDROID
IF INAPP_INIT=0
INAPP_INIT=1
InAppHelper_Init()
ENDIF

IF INAPP_RECEPTOK<1
ok=JavaCall$("Shop:isReceiptDone")
IF ok=1
INAPP_RECEPTOK=1
INAPP_PURCHASE$="restored"
IF INAPP_PURCHASES$<>""
INAPP_PURCHASE$=INAPP_PURCHASES$
INAPP_PURCHASES$=""
INAPP_STATUS$=""
INAPP_ACTIVATE$=""
JavaCall$("fullscreen")
ENDIF
ENDIF
ENDIF

IF INAPP_STORE$="No" THEN INAPP_STORE$=JavaCall$("Shop:GetAppStoreName")
IF INAPP_STATUS$="Activate" AND INAPP_STORE$<>"No"
INAPP_ERROR_TIMER=0
LOCAL result$=JavaCall$("Shop:Activated")
IF LEFT$(result$, 4)="fail" THEN ok=-1
IF LEFT$(result$, 4)="succ" THEN ok=1
LOCAL isOnline=InAppPurchase_isOnline()
IF ok=1
JavaCall$("Shop:ActivateReset")
INAPP_RECEPTOK=0;
INAPP_PURCHASES$=StringField$(result$, 3, ":")
ELSEIF ok=-1 //OR isOnline=0
JavaCall$("Shop:ActivateReset")
INAPP_STATUS$=""
INAPP_ACTIVATE$=""
INAPP_ERROR$="cancelled or failed"
INAPP_ERROR_TIMER=0
ENDIF
ENDIF

?ENDIF
ENDFUNCTION
// **************************** INAPP SHOP FUNCTIONS ENDS HERE ****************************

// *** HELPER FUNCTIONS ****
FUNCTION InAppHelper_SetSku: shop$, i
LOCAL sku$=InAppConfig_Sku2Names$(i, shop$)
LOCAL sgeneral$=InAppConfig_Sku2Names$(i, "general")
IF sku$<>"" AND sku$<>sgeneral$ AND sku$<>"0"
JavaCall$("Shop:SetSku:"+sgeneral$+":"+shop$+":"+sku$)
ENDIF
ENDFUNCTION

FUNCTION InAppHelper_Init:
?IFDEF ANDROID
// items for the store.

FOR i=0 TO INAPP_NR_OF_ITEMS-1
JavaCall$("Shop:SetSku:android:"+InAppConfig_Sku2Names$(i, "general")+":"+InAppConfig_Sku2Names$(i, "general"))
InAppHelper_SetSku("com.google.play", i)
InAppHelper_SetSku("com.ouya.shop", i)
InAppHelper_SetSku("com.amazon.apps", i)
InAppHelper_SetSku("com.samsung.apps", i)
InAppHelper_SetSku("com.yandex.store", i)
InAppHelper_SetSku("com.nokia.nstore", i)
InAppHelper_SetSku("Appland", i)
InAppHelper_SetSku("SlideME", i)
InAppHelper_SetSku("cm.aptoide.pt", i)
NEXT
JavaCall$("Shop:Init")
INAPP_STORE$=JavaCall$("Shop:GetAppStoreName")
?ENDIF
ENDFUNCTION

// hash an item to save locally when a purchase have been succed.
FUNCTION InAppHelper_HashID$: iID$
LOCAL DID$=PLATFORMINFO$("ID")+iID$
DID$=ENCRYPT$(DID$, LEFT$(DID$, 5))
DID$=HashNumber(DID$)+""+HashNumber(PLATFORMINFO$("ID"))+""+HashNumber(iID$)+""+472882049
RETURN DID$
ENDFUNCTION


Then you can use the shared internal SKU, named fullretail, when you calling the IAP functions. This due various shops require various named SKU, but wanted to call it with one shared SKU.

Also in AndroidManifest,xml you also require this one:

Code (glbasic) Select

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.spacefractal.greedymouse"
      android:installLocation="preferExternal"
      android:versionCode="208"
      android:versionName="16.02.08">
    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="22" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false" />

<supports-screens android:resizeable="false"
  android:smallScreens="true"
  android:normalScreens="true"
  android:largeScreens="true"
  android:xlargeScreens="true"
  android:anyDensity="true" />

  <application android:label="Greedy Mouse" android:isGame="true" android:hardwareAccelerated="true" android:icon="@drawable/icon" android:banner="@drawable/banner" android:debuggable="false">
  <meta-data android:name="com.google.android.gms.version" android:value="4323000"/>
  <activity android:name="org.libsdl.app.SDLActivity"
android:label="Greedy Mouse"
android:screenOrientation="sensorLandscape"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard"
>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


You do might not require the Android TV stuff of course, if you dont using GameInput API or using remappable KEY() for the game controller.

ONE more thing, which im might forget in the HELP file, is you also require to add few things to \distribute\Android\res\values\strings.xml:

Code (glbasic) Select

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name"Your Title Name</string>
<string name="Force_TV_720">1</string>
<string name="NoSDLmixer">false</string>
<string name="com.google.play">PUT THERE YOUR APPLICATION PUBLIC KEY</string>
<string name="OUYA_PUBLIC_KEY">YOUR OUYA DEV KEY</string>
<string name="Admob_ca_app_pub">ADMOB APPKEY FOR ADS</string>

</resources>


Hopefully im have not break something. Im can also not update it before around end of aug. Some the strings in the strings.xml might have been missed with the ads system... why the ads diddent work.

Also if you can use LOGCAT, then its would been much easier, because its often tell, what  went wrong.

Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

spacefractal

#5
also make sure InAppPurchase_Update() is also called soon the app start (and not just in the main loop). The first InAppPurchase_Update() call will also init the shop, which also take some time, and its also asyncron. Which means, your code countinue to running, while its init.

Also if the Google Service version number is wrong, then the correct version number would been output to the LOGCAT as well. You might have newer version of 4323000. This can happens.

Hence using LOGCAT is very important (_Logview.bat in Compiler\platform\android\bin), when the correct device driver is installed with cable in.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

MrPlow

For my version I only use some of those permissions....I am re-enabling my IAPs but past buyers still get the app without ads so I expect my iaps will work with only these...I expect the leanback references where for TV etc?

<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="18" />
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.WAKE_LOCK" />

   <!-- <uses-permission android:name="android.permission.BLUETOOTH" /> -->
   <uses-permission android:name="com.android.vending.BILLING" />
   <!-- <uses-permission android:name="android.permission.VIBRATE" /> -->
Comp:
Speccy-48k, Speccy-128k, Amigas, PCs

spacefractal

#7
minSdkVersion v9 is Android 2.3, which is no longer supported. Im will not checking with Android 2.x at all and im dont have those devices anymore. In the future, Android 4 would been required, which is v14. Im might go a least Android 4.1, which is v16. The newest version im have used is Android 5.1, where im utility full screen (v22). Im havent checked Android M yet.

This is no longer problem today, when we thinking the insanly hugo popular Pokomon Go app require v19 anyway. Im dont want to try to testing this on older systems. This is just like iOS, where iOS7 might been the required minimum now.

PS. Not all permissions as im use might required in your app. BILLING and INTERNET is the most important permissions. Etc the BLUETOOTH and VIBRATE ones.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

msx

This is the LOGCAT.

Still not working.  :'(

Code (glbasic) Select
Android Debug Bridge version 1.0.32
List of devices attached
0123456789ABCDEF        device

--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
I/glbasic (16225): surfaceDestroyed()
I/SDL     (16429): ---------------------------------------------
I/SDL     (16429): ---         Glbasic Start                 ---
I/SDL     (16429): ---------------------------------------------
I/SDL     (16429): onCreate
I/glbasic (16429): SDK: 17
I/glbasic (16429): external files dir is /data/data/com.crislosangames.test/files
I/glbasic (16429): 8
I/glbasic (16429): DPI 159
I/glbasic (16429): isTV:True
I/glbasic (16429): Unable to create encryption key or Ouya not supported
I/glbasic (16429): java.io.FileNotFoundException: Keys/key.der
I/glbasic (16429):      at android.content.res.AssetManager.openAsset(Native Method)
I/glbasic (16429):      at android.content.res.AssetManager.open(AssetManager.java:315)
I/glbasic (16429):      at android.content.res.AssetManager.open(AssetManager.java:289)
I/glbasic (16429):      at org.libsdl.app.SDLActivity.onCreate(SDLActivity.java:351)
I/glbasic (16429):      at android.app.Activity.performCreate(Activity.java:5122)
I/glbasic (16429):      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081)
I/glbasic (16429):      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2307)
I/glbasic (16429):      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2395)
I/glbasic (16429):      at android.app.ActivityThread.access$600(ActivityThread.java:162)
I/glbasic (16429):      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
I/glbasic (16429):      at android.os.Handler.dispatchMessage(Handler.java:107)
I/glbasic (16429):      at android.os.Looper.loop(Looper.java:194)
I/glbasic (16429):      at android.app.ActivityThread.main(ActivityThread.java:5392)
I/glbasic (16429):      at java.lang.reflect.Method.invokeNative(Native Method)
I/glbasic (16429):      at java.lang.reflect.Method.invoke(Method.java:525)
I/glbasic (16429):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
I/glbasic (16429):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
I/glbasic (16429):      at dalvik.system.NativeStart.main(Native Method)
I/glbasic (16429): Creating SoundPool instances...
I/glbasic (16429): SoundPool instances created
I/glbasic (16429): device: D101
I/glbasic (16429): onCreate done
I/glbasic (16429): OnResume()
I/glbasic (16429): OnResume() end
I/glbasic (16429): surfaceCreated()
I/glbasic (16429): surfaceChanged()
I/SDL     (16429): pixel format RGB_565
I/glbasic (16429): startApp, thread
I/SDL     (16429): hint screensize to glb
I/glbasic (16429): glb_notify_screen_size 1024x552
I/SDL     (16429): SDL_Android_Init()
I/SDL     (16429): SDL_Android_Init() finished!
I/glbasic (16429): Can't init SDL.
I/glbasic (16429): Passed a NULL mutex
I/glbasic (16429): timer
I/glbasic (16429): rbow
I/glbasic (16429): rbow init
I/glbasic (16429): SDL_init video
I/glbasic (16429): SDL_GetVideoInfo = 1024x552 @ 0 bpp. Screen 1024x552
I/glbasic (16429): SDL 2.x mode
I/glbasic (16429): C++ calling SDL_CreateWindow (fs:1)
I/SDL     (16429): ceateGLContext
I/SDL     (16429): ceateEGLContext
I/SDL     (16429): [STUB] GL_SetSwapInterval
I/glbasic (16429): C++ SDL_CreateWindow stuff finished
I/glbasic (16429): get accurate timer - 1st call
I/glbasic (16429): flip - 1st call
I/glbasic (16429): BGRA ext supported
I/glbasic (16429): Texture size limit: 4096
I/glbasic (16429): init fbo
I/glbasic (16429): 2D VP
I/glbasic (16429): OGRB init [OK]
I/glbasic (16429): Cptn
I/glbasic (16429): Network
I/glbasic (16429): Input
I/glbasic (16429): Window mode
I/glbasic (16429): Create DXin
I/glbasic (16429): getexe
I/glbasic (16429): cd
I/glbasic (16429): exepath=curdir= /data/data/com.crislosangames.test
I/glbasic (16429): shoeboxing...
I/glbasic (16429): init gettimer
I/glbasic (16429): clear screen
I/glbasic (16429): flip
I/glbasic (16429): mk2D
I/glbasic (16429): finding font...
I/glbasic (16429): SDL audio: wanted stereo 16-bit 44.1kHz, 1024 frames buffer
I/glbasic (16429): SDL audio: got stereo 16-bit 44.1kHz, 4096 frames buffer
I/glbasic (16429): open sound: 44100 Hz 2 chan, buffers 1024, format -32752
I/glbasic (16429): Init Finalized
I/glbasic (16429): [GLB]->InAppPurchase_Activate:com.crislosangames.test.purchase

spacefractal

did you make sure to use the update command, in a loop and in the start?

Also im cant help very much right now, because im prepare for a trip tomorrow and is gone for a week. But im can do look into your code eventuelly when im are back and home again.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

msx

I have sent you a private

msx

Copy the code I use to see if someone can help me. I do not know if someone else uses InApp apart from @spacefractal and @MrPow.

test.gbas

Code (glbasic) Select
// --------------------------------- //
// Project: test
// Start: Friday, July 22, 2016
// IDE Version: 14.001

InAppPurchase_Update()

// SETCURRENTDIR("Media") // go to media files
SYSTEMPOINTER TRUE

LOCAL mx, my, b1, b2

WHILE 1

PRINT "Store ONLINE: "+InAppPurchase_isOnline(),0,0

PRINT "Price: "+InAppPurchase_Price$("licensed"),0,20

PRINT "Available: "+InAppPurchase_isAvailable("licensed"),0,40

PRINT "Activate: "+InAppPurchase_Activate("licensed"),0,60

SHOWSCREEN

InAppPurchase_Update()

MOUSESTATE mx, my, b1, b2

IF b1 THEN END

WEND


InAPP.gbas

Code (glbasic) Select
// --------------------------------- //
GLOBAL INAPP_ERROR$=""      // When a error in a purchase or when restoring.
GLOBAL INAPP_ISONLINE=0     // is network on?
GLOBAL INAPP_PURCHASE$=""   // when a purchase just have been succed.
GLOBAL INAPP_ACTIVATE$=""   // a user is doing the order progress (chould should "progress" to user, if INAPP_ACTIVATE have any content).
GLOBAL INAPP_STATUS$=""     // wating for a callback for either retore or purchase (this can been used when pause was activated).

// **************************** CONFIGURATIONS START HERE ****************************
GLOBAL INAPP_NR_OF_ITEMS=1; // numbers of inapp items you want to uses (this is due init to Android). Not needed for iOS.

// InAppConfig_SkuNames$ configuration for various Appstores. In the game, you might want to only
// use one SKU, which is why its need to been find and convert the ID to the correct name
// for the shop. Also ID numbers is also required for init ITEMS for Android.
//
// For iOS, you also need configuere the Sku Names in the MKStoreKitConfigs.plist too. That
// can been done using xCode. They should named the same with the SKU you configuried in the
// iTunes Connect and similar interfaces.
//
// This can take some time to setup that one.
//
// SKUS should not confict each other on Android stores, or OpenIAP might fails to fid the correct sku, that even on OUYA.
FUNCTION InAppConfig_Sku2Names$: iID$, store$
        // check name for "The Premium Key"

        IF iID$="0" OR iID$="licensed"
                IF store$="com.ouya.shop"      THEN RETURN ""
                IF store$="gamestick.tv.shop"  THEN RETURN "" // SKU is named URL in GameStick Portal
                IF store$="com.google.play"    THEN RETURN "mycompany.purchased" // Name in Google Play Console
                IF store$="general" OR store$="android" THEN RETURN "licensed" // the shared name for this sku for Android Stores (should not conflict allready used)
                IF store$="microsoft.windows"  THEN RETURN "windows.fullretail"
                iID$="licensed"
        ENDIF
        RETURN iID$
ENDFUNCTION


// The Public key from YOUR APPLICATION'S PUBLIC KEY, you get from the Dev Console for that store.
// those Security keys os fpr Android only and is not needed for iOS.
FUNCTION InAppConfig_PublicKeys$: store$
        INAPP_DEVKEY = HashNumber("0123456789") // just put a totally random sucure key for the hash number (this using for other systems as well).

        IF store$="com.google.play" OR store$=1 THEN RETURN "Long_Number_Sample_Aij9ylltNxktl3lLV2ClBvueZ5hA4Iq7j73KClCBIMW1YZam+2XkQahANmNiTUDEQwPUaH2Rf+qWJxXydDTRCG0uv/DjHtJxCJ18sO+WuS7PWfle8RCyTCIXLsuBCT3YArEnC32jAiMqUA40zllVcJbPAgRU+U/8Katx7igTYeKAOunYi/Y0g8EY+NLRxlMtiRvIVsrz4Hv6Gz5p9a+41oLSf3GouGttQ3IOvPJeuGt2ZOhU2z1fX14cCtI3LGqKJrTWv99tha5g033cO7Id+VOurenRVyYVcHXZwz1yDnuvJlmuNvKKCrOlmmL2YGFrbJfsXIvb7fm+GQF+79CGdywIDAQAB"
        IF store$="microsoft.windows" THEN RETURN HashNumber(InAppConfig_PublicKeys$("com.google.play"))
ENDFUNCTION



// **************************** CONFIGURATIONS ENDS HERE ****************************
//
//
//
//
//
// **************************** INAPP SHOP FUNCTIONS START HERE ****************************
?IFDEF IPHONE
//      IMPORT "C" int StoreIsOnline(int) // parents check if the inapp is disabled (0=init once, 1=reinit again).
//      IMPORT "C" int StoreIsFeaturePurchased(const char*, int) // checks if the feature have been purchased
//      IMPORT "C" int StoreRestored() // is store have been complete (1) or failed (-1)?
//      IMPORT "C" void StoreRestore() // Restore any previous purchased items (required on iOS).
//      IMPORT "C" int StoreActivate(const char*) // User have just pressed on the buys button in your app.
//      IMPORT "C" const char* StoreGetPrice(const char*) // Get a Price for the product.
//      IMPORT "C" int StoreActivated() // check the purchasing item....
?ENDIF

GLOBAL INAPP_INIT=0
GLOBAL INAPP_ERROR_TIMER=0  // time before error message vanish.
GLOBAL INAPP_STORE$=""      // the store name going to been used.
GLOBAL INAPP_DEVKEY = 0     // a dev key
GLOBAL INAPP_PURCHASES$=""  // a recent purchase, but waiting for receipt (ANDROID ONLY)
GLOBAL INAPP_RECEPTOK = 0   // Have recept to been checked (ANDROID ONLY)
GLOBAL INAPP_PAUSE = 0
GLOBAL INAPP_SAMSUNGID$     // Group ID for Samsung Apps, is init automatic in the init, based on publickey.
GLOBAL INAPP_INACTIVATESTARTED=0


//
// is the store online?
FUNCTION InAppPurchase_isOnline:
        ?IFDEF WIN32
                InAppConfig_PublicKeys$("nothing")
                RETURN 0
        ?ENDIF

        ?IFDEF IPHONE
                LOCAL ok //=StoreIsOnline(0)
                RETURN ok
        ?ENDIF

        ?IFDEF ANDROID
                LOCAL ok=JavaCall$("Shop:IsOnline")
                RETURN ok;
        ?ENDIF
ENDFUNCTION

// get a price of the current product
FUNCTION InAppPurchase_Price$: iID$
        STATIC IDDD$
        STATIC IDPRICE$
        STATIC counter=0


        iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)

        ?IFDEF WIN32
                RETURN "some price"
        ?ENDIF

        ?IFDEF IPHONE
//              IF IDDD$=iID$ AND IDPRICE$<>"unknown" THEN RETURN IDPRICE$
//              LOCAL price$=StoreGetPrice(iID$)
//              price$=TRIM$(price$)
//              IDDD$=iID$
//              IDPRICE$=price$
//              RETURN price$
        ?ENDIF

        ?IFDEF ANDROID
                IF IDDD$=iID$ AND IDPRICE$<>"unknown" THEN RETURN IDPRICE$
                LOCAL price$=JavaCall$("Shop:GetPrice:"+iID$)
                IF price$="-1" THEN price$="offline"
                IDPRICE$=price$
                RETURN price$
        ?ENDIF
ENDFUNCTION

// is the inapp item available? Etc have you brought the item (1) or not (0)? (consumable is not supported yet)
// for some secure reasons, true and false is easy to been hacked, then its uses some hash to get a bit harder to crach.
//
// to also prevent tapping source for exeample from java, checkout fake products and make sure is returned false, which
// give a constant hash number for that. This could been done in various places in your app.
FUNCTION InAppPurchase_isAvailable: iID$
        LOCAL orig$=iID$
        LOCAL ok%=0

        IF INAPP_DEVKEY=0 THEN InAppConfig_PublicKeys$("")
        IF INAPP_DEVKEY=0 THEN RETURN 0
        orig$=InAppConfig_Sku2Names$(iID$, "android")
        iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)

        ?IFDEF WIN32
                ok=INAPP_DEVKEY //StoreWin(iID$, INAPP_DEVKEY)
        ?ENDIF

        ?IFDEF IPHONE
                //ok=StoreIsFeaturePurchased(iID$, INAPP_DEVKEY)
        ?ENDIF

        ?IFDEF ANDROID
                ok=JavaCall$("Shop:isAvailable:"+iID$+":"+INAPP_DEVKEY)
        ?ENDIF

        ok=HashNumberBig(ok)
        ok=ok-ABS(HashNumberBig(InAppConfig_PublicKeys$("microsoft.windows")))
        ok=ok*HashNumber(-ok)
        ok=ASL(ok, 4)
        ok=ok*HashNumber(orig$)
        ok=ok-HashNumber(INAPP_DEVKEY)
        ok=ABS(ok)
        RETURN ok
ENDFUNCTION

?IFDEF WIN32
        FUNCTION StoreWin: iID$, keys
                IF INAPP_DEVKEY=0 THEN InAppConfig_PublicKeys$("nothing")
                IF INAPP_DEVKEY=0 THEN RETURN 0
                LOCAL ok=0

                IF iID$="jdg445Ffk439Ffkdd3t" THEN RETURN 0
                RETURN keys // allwys return a success.
                RETURN 0 // allways return a fail.
        ENDFUNCTION
?ENDIF

// Start the payment progress (etc you have pressed on a purchase button).
// On windows, the purchase is allways succes. On iOS and Android, a
// GLB_ON_PAUSE/() can been called here, so you might checks INAPP_STATUS$ for
// eventuelly checks if there us a purchase ongoing or not in there.
FUNCTION InAppPurchase_Activate: iID$
        INAPP_INACTIVATESTARTED=1
        IF INAPP_STATUS$<>"" AND INAPP_STATUS$<>"Activate"
                INAPP_ERROR$="store progress ongoing"
                RETURN
        ENDIF

        iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)
        ?IFDEF WIN32
                InAppPurchase_Finished(iID$)
                RETURN TRUE
        ?ENDIF

        ?IFDEF IPHONE
//              LOCAL ok=StoreActivated() // if user have cancelled purchasem but purcahse did got succes, then the purchase should been activated
//              IF ok=1
//                      INAPP_PURCHASE$=iID$
//                      INAPP_STATUS$=""
//                      RETURN
//              ENDIF
//              StoreActivate(iID$)
//              INAPP_STATUS$="Activate"
//              INAPP_ACTIVATE$=iID$
//              RETURN TRUE
        ?ENDIF

        ?IFDEF ANDROID
                IF INAPP_STATUS$=""
                        DEPRINT("InAppPurchase_Activate:"+iID$)
                        JavaCall$("Shop:Activate:"+iID$)
                        INAPP_STATUS$="Activate"
                        INAPP_ACTIVATE$=iID$
                ENDIF
        ?ENDIF
        ENDFUNCTION

// A Purchase have just been activated and then its should been saved here locally.
// Only required for Windows for Fake purchases to save the purchases. Its doing
// automatic on Android as well iOS.
FUNCTION InAppPurchase_Finished: iID$
        INAPP_PURCHASE$=iID$
        IF INAPP_ERROR$="" THEN INAPP_ERROR$="success"
        iID$=InAppConfig_Sku2Names$(iID$, INAPP_STORE$)
        ?IFDEF Win32
                SetStr(InAppHelper_HashID$(iID$), "Purchase", 1)
        ?ENDIF
ENDFUNCTION

// you must do a restore feature for IOS to keep Apple happy to recover all
// perlament purchased items. Dont forget to check the features is Available
// trought InAppPurchase_isAvailable(), which is not automatic done.
//
// a succes would sent a INAPP_PURCHASE$="restored". If user failed to restore
// then a error would been sent to INAPP_ERROR$
//
// This is done automatic on Android and OUYA on startup, but this is required
// for iOS.
FUNCTION InAppPurchase_Restore:
        IF INAPP_STATUS$<>"" THEN RETURN

        ?IFDEF WIN32
                FOR i=0 TO 100
                        LOCAL iID$=InAppConfig_Sku2Names$(i, INAPP_STORE$)
                        IF iID$<>""
                                InAppPurchase_Activate(iID$)
                        ELSE
                                RETURN
                        ENDIF
                NEXT
        ?ENDIF

        ?IFDEF IPHONE
//              StoreRestore()
//              INAPP_STATUS$="Restore"
//              INAPP_ERROR_TIMER=0
        ?ENDIF
ENDFUNCTION

// This is a updater function, which is required to been invoked in loop time.
// This function checkout ongoing purchases using callbacks. that why you need
// this around a SHOWSCREEN.
FUNCTION InAppPurchase_Update:
        LOCAL ok=0
        ?IFDEF ANDROID
                IF INAPP_RECEPTOK=1
                        INAPP_RECEPTOK=2
                        INAPP_ERROR$=""
                ENDIF
        ?ENDIF

        IF INAPP_ERROR$<>""
                INAPP_ERROR_TIMER=INAPP_ERROR_TIMER+0.1
                IF INAPP_ERROR_TIMER>60
                        INAPP_ERROR_TIMER=0
                        INAPP_ERROR$=""
                ENDIF
        ENDIF

        ?IFDEF WIN32
                IF INAPP_INIT=0
                        INAPP_INIT=1
                        INAPP_STORE$="microsoft.windows"
                        InAppConfig_PublicKeys$("")
                        INAPP_PURCHASE$="restored"
                        INAPP_RECEPTOK=2
                ENDIF
        ?ENDIF

        ?IFDEF IPHONE
//              IF INAPP_INIT=0
//                      INAPP_INIT=1
//                      INAPP_STORE$="apple.appstore.ios"
//                      INAPP_ISONLINE=StoreIsOnline(0)
//                      IF INAPP_ISONLINE<>0
//                              IF INAPP_RECEPTOK<1
//                                      INAPP_PURCHASE$="restored"
//                                      INAPP_RECEPTOK=1
//                              ENDIF
//                      ENDIF
//              ENDIF

//              IF INAPP_STATUS$="Activate"
//                      INAPP_ERROR_TIMER=0
//                      ok=StoreActivated()
//                      IF ok=1
//                              INAPP_PURCHASE$=INAPP_ACTIVATE$
//                              INAPP_STATUS$=""
//                              INAPP_ACTIVATE$=""
//                      ELSEIF ok=-1 OR (InAppPurchase_isOnline()=0)
//                              INAPP_STATUS$=""
//                              INAPP_ACTIVATE$=""
//                              INAPP_ERROR$="cancelled or failed"
//                              INAPP_ERROR_TIMER=0
//                      ENDIF
//              ENDIF

//              IF INAPP_STATUS$="Restore"
//                      ok=StoreRestored()
//                      IF ok=1
//                              INAPP_RECEPTOK=2
//                              INAPP_PURCHASE$="restored"
//                              INAPP_STATUS$=""
//                      ELSEIF ok=-1
//                              INAPP_ERROR$="failed"
//                              INAPP_STATUS$=""
//                              INAPP_ERROR_TIMER=0
//                      ENDIF
//              ENDIF
        ?ENDIF

        ?IFDEF ANDROID
                IF INAPP_INIT=0
                        INAPP_INIT=1
                        InAppHelper_Init()
                ENDIF

                IF INAPP_RECEPTOK<1
                        ok=JavaCall$("Shop:isReceiptDone")
                        IF ok=1
                                INAPP_RECEPTOK=1
                                INAPP_PURCHASE$="restored"
                                IF INAPP_PURCHASES$<>""
                                        INAPP_PURCHASE$=INAPP_PURCHASES$
                                        INAPP_PURCHASES$=""
                                        INAPP_STATUS$=""
                                        INAPP_ACTIVATE$=""
                                        JavaCall$("fullscreen")
                                ENDIF
                        ENDIF
                ENDIF

                IF INAPP_STORE$="No" THEN INAPP_STORE$=JavaCall$("Shop:GetAppStoreName")
                IF INAPP_STATUS$="Activate" AND INAPP_STORE$<>"No"
                        INAPP_ERROR_TIMER=0
                        LOCAL result$=JavaCall$("Shop:Activated")
                        IF LEFT$(result$, 4)="fail" THEN ok=-1
                        IF LEFT$(result$, 4)="succ" THEN ok=1
                        LOCAL isOnline=InAppPurchase_isOnline()
                        IF ok=1
                                JavaCall$("Shop:ActivateReset")
                                INAPP_RECEPTOK=0;
                                INAPP_PURCHASES$=StringField$(result$, 3, ":")
                        ELSEIF ok=-1 //OR isOnline=0
                                JavaCall$("Shop:ActivateReset")
                                INAPP_STATUS$=""
                                INAPP_ACTIVATE$=""
                                INAPP_ERROR$="cancelled or failed"
                                INAPP_ERROR_TIMER=0
                        ENDIF
                ENDIF

        ?ENDIF
ENDFUNCTION
// **************************** INAPP SHOP FUNCTIONS ENDS HERE ****************************

// *** HELPER FUNCTIONS ****
FUNCTION InAppHelper_SetSku: shop$, i
        LOCAL sku$=InAppConfig_Sku2Names$(i, shop$)
        LOCAL sgeneral$=InAppConfig_Sku2Names$(i, "general")
        IF sku$<>"" AND sku$<>sgeneral$ AND sku$<>"0"
                JavaCall$("Shop:SetSku:"+sgeneral$+":"+shop$+":"+sku$)
        ENDIF
ENDFUNCTION

FUNCTION InAppHelper_Init:
        ?IFDEF ANDROID
                // items for the store.

                FOR i=0 TO INAPP_NR_OF_ITEMS-1
                        JavaCall$("Shop:SetSku:android:"+InAppConfig_Sku2Names$(i, "general")+":"+InAppConfig_Sku2Names$(i, "general"))
                        InAppHelper_SetSku("com.google.play", i)
                        InAppHelper_SetSku("com.ouya.shop", i)
                        InAppHelper_SetSku("com.amazon.apps", i)
                        InAppHelper_SetSku("com.samsung.apps", i)
                        InAppHelper_SetSku("com.yandex.store", i)
                        InAppHelper_SetSku("com.nokia.nstore", i)
                        InAppHelper_SetSku("Appland", i)
                        InAppHelper_SetSku("SlideME", i)
                        InAppHelper_SetSku("cm.aptoide.pt", i)
                NEXT
                JavaCall$("Shop:Init")
                INAPP_STORE$=JavaCall$("Shop:GetAppStoreName")
        ?ENDIF
ENDFUNCTION

// hash an item to save locally when a purchase have been succed.
FUNCTION InAppHelper_HashID$: iID$
        LOCAL DID$=PLATFORMINFO$("ID")+iID$
        DID$=ENCRYPT$(DID$, LEFT$(DID$, 5))
        DID$=HashNumber(DID$)+""+HashNumber(PLATFORMINFO$("ID"))+""+HashNumber(iID$)+""+472882049
        RETURN DID$
ENDFUNCTION


Also attached screenshot of the result.

I hope someone can help me. Private data have been replaced by others. If someone needs to know the data that he send me a private.

Thanks.

spacefractal

As I'm wrote soon I'm home from vacation trip I'm look into the issue. Sorry for the delay.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

msx

You do not worry buddy, I know you're busy this week. I put it here if someone else knows how to help me.

Thank you very much.

MrPlow

Hi msx

You are getting a value output so thats a good sign...I am a bit rusty on the IAP functions, but I have to add a new one myself soon.

You have added your manager sku item to playstore for the apk as well?

There are two numbers the number before being purchased and the number result after a successful purchase.

You can test against the non-purchase number IF InAppPurchase_isAvailable("licensed")<>xxxxxxxxx but obviously better to test against the purchase version.


InappPurchase_activate is the buying process so attach to a 'button press' and move your inappPurchase_update() to top of code.


Comp:
Speccy-48k, Speccy-128k, Amigas, PCs