Google IAP Android help please

I have been trying for days to get Google IAP working, to no avail.

Can someone please help me out, this is beyond despressing now lol.

In adb log I only get this:
Please call init before trying to purchase products.

Google Play is all set up nicely as per the guides and I am currently testing from an internal testing track from within Google Play.

I have also tried all the help in Solar2d forums website etc…
I have seriously no clue as what to do next.

Thanking you in anticipation.

Code below:

Main.lua
–in app purchases--------------------------------------------------------------------------
local store=require(“plugin.google.iap.billing”);

local function transactionListener(e)
if(e.name==“init”)then
print(“e.name INIT -------- WE ARE INSIDE INAPP IAPLISTENER - INIT”);
local function openStore()
print(“After 8 seconds the state of store is:”,store.isActive);
end
timer.performWithDelay(8000,openStore,1);
elseif(e.name==“storeTransaction”)then
if not(e.transaction.isError)then
print(“e.name inside storeTransaction”);
–e.transaction,state will return ‘purchased’ / ‘restored’ / ‘cancelled’ / ‘failed’
–google iap also has consumed and refunded.
–consumed is for allowing players to buy consumables again
if(e.transaction.state==“purchased”)then
print(“Store Purchase”,e.transaction.productIdentifier);
if(e.transaction.productIdentifier==“com.xxx.1”)then
–do whatever
elseif(e.transaction.productIdentifier==“com.xxx.2”)then
–do whatever
elseif(e.transaction.productIdentifier==“com.xxx.3”)then
–do whatever
end
elseif(e.transaction.state==“consumed”)then

        end
    else
        print("There was an error in storeTransaction",e.transaction.errorType,e.transaction.errorString);
    end
    
--store.finishTransaction(e.transaction);
end

end
local function productListener(e)
print(“WE ARE INSIDE IAP ITEMSLISTENER”);
for li=1,#e.products do
print(e.products[li].title);
print(e.products[li].price);
print(e.products[li].description);
print(e.products[li].productIdentifier);
print(e.products[li].price);
print(e.products[li].localizedPrice);
if(e.products[li].productIdentifier==“com.xxx.1”)then
shop1Txt.text=e.products[li].localizedPrice;
end
if(e.products[li].productIdentifier==“com.xxx.2”)then
shop2Txt.text=e.products[li].localizedPrice;
end
if(e.products[li].productIdentifier==“com.xxx.”)then
shop3Txt.text=e.products[li].localizedPrice;
end
end
end
local productIdentifiers={“com.xxx.1”,“com.xxx.2”,“com.xxx.3”};
local function loadItems()
if(store.canLoadProducts)then
store.loadProducts(productIdentifiers,productListener);
end
end
purchaseJokerCoins1=function()
if(store.canMakePurchases)then
audio.play(sound.coin);
store.purchase(“com.xxx.1”);
else
native.showAlert(“Purchase”,“In-app purchases are not allowed.”,{“OK”});
end
end
purchaseJokerCoins2=function()
if(store.canMakePurchases)then
audio.play(sound.coin);
store.purchase(“com.xxx.2”);
else
native.showAlert(“Purchase”,“In-app purchases are not allowed.”,{“OK”});
end
end
purchaseJokerCoins3=function()
if(store.canMakePurchases)then
audio.play(sound.coin);
store.purchase(“com.xxx.3”);
else
native.showAlert(“Purchase”,“In-app purchases are not allowed.”,{“OK”});
end
end

timer.performWithDelay(5000,store.init(transactionListener),1);

Build.settings - the relevant bits
settings =
{
orientation =
{
– Supported values for orientation:
– portrait, portraitUpsideDown, landscapeLeft, landscapeRight
default = “landscapeRight”,
supported = {“landscapeLeft”,“landscapeRight”},
},

--
-- Android section
--
android =
{
	usesPermissions =
	{
		"android.permission.INTERNET",
        "android.permission.ACCESS_NETWORK_STATE",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "com.android.vending.BILLING",
        --"android.permission.GET_ACCOUNTS",
        "android.permission.ACCESS_COARSE_LOCATION",
        "android.permission.ACCESS_FINE_LOCATION",
        --"android.permission.RECORD_AUDIO",
	},
    minSdkVersion = "21", --version 5+
    applicationChildElements =
    {
        [[
            <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"/>  -- replace with your app id. See: https://goo.gl/fQ2neu
        ]],
    },
},

Config.lua - in full
application =
{
content =
{
width = 1536,
height = 2048,
scale = “letterbox”,
fps = 60,

	--[[
	imageSuffix =
	{
		    ["@2x"] = 2,
		    ["@4x"] = 4,
	},
	--]]
},
license =
{
    google =
        {
              key = "MIIBIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        },
},

}

The post is fairly hard to read, but I just use iap_badger from happymongoose here:

They have a couple of examples in the repo that might be helpful. if you are trying to verify Amazon receipts you can also pull my changes (that

1 Like

Agramonte,

Thank you very much for your reply.

I apologise for submitting the content without any pre-formatting, I just copied and pasted and thought it would keep the formatting.

I do take your suggestion on IAP Badger, but I would like to take care of this myself, which is why I would like to use the IAP plugin and commands therein.

I have included my code again, so someone can take a look. If someone cracks this I would be forever grateful.
When I press any of the buttons that would trigger a purchase I get this in adb logcat:
Please call init before trying to purchase products.

Many thanks.

indent preformatted text by 4 spaces

build.settings

settings =
{

--
-- Android section
--
android =
{
	usesPermissions =
	{
		"android.permission.INTERNET",
        "android.permission.ACCESS_NETWORK_STATE",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "com.android.vending.BILLING",
        "com.android.vending.CHECK\_LICENSE",
        --"android.permission.GET_ACCOUNTS",
        "android.permission.ACCESS_COARSE_LOCATION",
        "android.permission.ACCESS_FINE_LOCATION",
        --"android.permission.RECORD_AUDIO",
	},
    minSdkVersion = "21", --for Android 5+ https TLS2 etc
    applicationChildElements =
    {
        [[
            <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-XXXXXXXXXXXXX~XXXXXXXX"/>  -- replace with your app id. See: https://goo.gl/fQ2neu
        ]],
    },
},

--
-- iOS section
--
iphone =
{
	xcassets = "Images.xcassets",
	plist =
	{
        
        --      NSAppTransportSecurity = 
		--{
		--	NSExceptionDomains = 
		--	{
		--		["toparcadeapps.com"] =
		--		{
		--			NSIncludesSubdomains = true,
		--			NSExceptionRequiresForwardSecrecy = false,
		--			NSExceptionAllowsInsecureHTTPLoads = true,
		--			--NSAllowsArbitraryLoads = true,
		--		}
		--	},
		--},
              
		UIStatusBarHidden = false,
		UILaunchStoryboardName = "LaunchScreen",
	},
},

--
-- Plugins section
--
plugins =
{        
    ["plugin.google.iap.billing"]=
    {
          -- required
          publisherId = "com.coronalabs"
          --supportedPlatforms = {android = true}, --tried with and without
    },
    
    --["plugin.reviewPopUp"] =
    --{
     --     publisherId = "tech.scotth",
    --},
    
    
    -- Appodeal
    ['plugin.appodeal.beta.base'] = { publisherId = 'com.coronalabs', supportedPlatforms = { iphone=true, android=true } }, ['plugin.appodeal.beta.FacebookAudience'] = { publisherId = 'com.coronalabs', supportedPlatforms = { iphone=true, android=true } }, ['plugin.appodeal.beta.AmazonAds'] = { publisherId = 'com.coronalabs', supportedPlatforms = { iphone=true, android=true } }, ['plugin.appodeal.beta.GoogleAdMob'] = { publisherId = 'com.coronalabs', supportedPlatforms = { iphone=true, android=true } }, ['plugin.appodeal.beta.AppLovin'] = { publisherId = 'com.coronalabs', supportedPlatforms = { iphone=true, android=true } }

    
    
    -- Base
    --['plugin.appodeal.base'] = { publisherId = 'com.coronalabs' },
    -- All types
    --['plugin.appodeal.Bidmachine'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.GoogleAdMob'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.A4G'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.AppLovin'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.FacebookAudience'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.MyTarget'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.Smaato'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.StartApp'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.Unity'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.Yandex'] = { publisherId = 'com.coronalabs' },
    -- Interstitial
    --['plugin.appodeal.AdColony'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.AmazonAds'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.IronSource'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.Ogury'] = { publisherId = 'com.coronalabs' },['plugin.appodeal.Vungle'] = { publisherId = 'com.coronalabs' },
},

--
-- Project section
--
excludeFiles =
{
	-- Exclude unnecessary files for each platform
	all = { "Icon.png", "Icon-*dpi.png", "Images.xcassets", },
	android = { "LaunchScreen.storyboardc", },
},

}

indent preformatted text by 4 spaces

config.lua
application =
{
content =
{
width = 1536,
height = 2048,
scale = “letterbox”,
fps = 60,

	--[[
	imageSuffix =
	{
		    ["@2x"] = 2,
		    ["@4x"] = 4,
	},
	--]]
},
license =
{
    google =
        {
              key = "MIIBIjXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        },
},

}

main.lua
–in app purchases--------------------------------------------------------------------------
local store=require(“plugin.google.iap.billing”); --is it this one or v3 ???

local function transactionListener(e)
    if(e.name=="init")then
        print("e.name INIT -------- WE ARE INSIDE INAPP IAPLISTENER - INIT"); --this is the only value that gets printed
        local function openStore()
            print("After 8 seconds the state of store is:",store.isActive); --always returns false why?
        end
        timer.performWithDelay(8000,openStore,1);
    elseif(e.name=="storeTransaction")then
        if not(e.transaction.isError)then
            print("e.name inside storeTransaction -------------- apparently no errors lol");
            --e.transaction,state will return 'purchased' / 'restored' / 'cancelled' / 'failed'
            --google iap also has consumed and refunded.
            --consumed is for allowing players to buy consumables again
            if(e.transaction.state=="purchased")then
                print("Store Purchase",e.transaction.productIdentifier);
                if(e.transaction.productIdentifier=="com.xxx.1")then
                    player.myCoins=player.myCoins+1000;
                    saveFile("gameData.dat");
                    saveFileEnc("gameDataEnc.dat");
                    --consume purchase for google iap
                    store.consumePurchase("com.xxx.1");
                elseif(e.transaction.productIdentifier=="com.xxx.2")then
                    player.myCoins=player.myCoins+2000;
                    saveFile("gameData.dat");
                    saveFileEnc("gameDataEnc.dat");
                elseif(e.transaction.productIdentifier=="com.xxx.3")then
                    player.myCoins=player.myCoins+10000;
                    saveFile("gameData.dat");
                    saveFileEnc("gameDataEnc.dat");
                end
            elseif(e.transaction.state=="consumed")then
                if(e.transaction.productIdentifier=="com.xxx.1")then
                    print("CONSUMED BET50 POKER JOKER COINS 1 - REACTIVATE IT AS IT IS A CONSUMABLE ITEM");
                end
            elseif(e.transaction.state=="refunded")then
                print("PRODUCT REFUNDED - REMOVE QTY FROM FILE???");
            end
        else
            print("There was in error in storeTransaction",e.transaction.errorType,e.transaction.errorString);
        end
        
--store.finishTransaction(e.transaction);
    end
end
local function productListener(e)
    print("WE ARE INSIDE IAP ITEMSLISTENER");
    for li=1,#e.products do
        print(e.products[li].title);
        print(e.products[li].price);
        print(e.products[li].description);
        print(e.products[li].productIdentifier);
        print(e.products[li].price);
        print(e.products[li].localizedPrice);
        if(e.products[li].productIdentifier=="com.xxx.1")then
            shop1Txt.text=e.products[li].localizedPrice;
        end
        if(e.products[li].productIdentifier=="com.xxx.2")then
            shop2Txt.text=e.products[li].localizedPrice;
        end
        if(e.products[li].productIdentifier=="com.xxx.3")then
            shop3Txt.text=e.products[li].localizedPrice;
        end
    end
end
local productIdentifiers={"com.xxx.1","com.xxx.2","com.xxx.3"};
local function loadItems()
    if(store.canLoadProducts)then
        store.loadProducts(productIdentifiers,productListener);
    end
end
purchaseJokerCoins1=function()
      if(store.canMakePurchases)then
            audio.play(sound.coin);
            store.purchase("com.xxx.1");
      else
            native.showAlert("Purchase","In-app purchases are not allowed.",{"OK"});
      end
end
purchaseJokerCoins2=function()
      if(store.canMakePurchases)then
            audio.play(sound.coin);
            store.purchase("com.xxx.2");
      else
            native.showAlert("Purchase","In-app purchases are not allowed.",{"OK"});
      end
end
purchaseJokerCoins3=function()
      if(store.canMakePurchases)then
            audio.play(sound.coin);
            store.purchase("com.xxx.3");
      else
            native.showAlert("Purchase","In-app purchases are not allowed.",{"OK"});
      end
end

timer.performWithDelay(5000,store.init(transactionListener),1);

i think the problem is in calling the store.init …

it should be something like this

timer.performWithDelay(5000,function() store.init(transactionListener) end)

because a timer calls a function … and you are not calling the code as a function

hope it helps

1 Like