• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Android [SOLVED] HELP! In-App Purchases Not Working :(

J

Jarrell Cobbs

Guest
Hello Community :)

This is JCGam3z, a well-known app developer

I'm having trouble getting in-app purchases to work in my store! Any assistance would be greatly appreciated. I've been at this for 5 DAYS now and it's getting really frustrating :(

Here is my code...

***Create Event***

var map_create = true;
if file_exists("iap_data.json")
{
global.purchaseMap = ds_map_secure_load("iap_data.json");
if ds_exists(global.purchaseMap, ds_type_map)
{
var product = "iap_test3";
}
if ds_map_exists(global.purchaseMap, product)
{
map_create = false;
if ds_map_find_value(global.purchaseMap, product) == 0
{
ads_enable(display_get_gui_width() / 2, 0, 0);
}
}
}
if map_create
{
global.purchaseMap = ds_map_create();
var product1 = "iap_test3";
ds_map_add(global.purchaseMap, product1, 0);
ds_map_secure_save(global.purchaseMap, "iap_data.json");
}
var pNoAds = ds_map_create();
var productList = ds_list_create();
ds_map_add(pNoAds, "id", "iap_test3");
ds_map_add(pNoAds, "title", "No Ads");
ds_map_add(pNoAds, "type", "Durable");
ds_list_add(productList, pNoAds);
iap_activate(productList);
ds_map_destroy(pNoAds);
ds_list_destroy(productList);



***IAP Async Event***

var val = ds_map_find_value(iap_data, "type");
switch (val)
{
case iap_ev_purchase:
var map = ds_map_create();
var purchase_id = ds_map_find_value(iap_data, "index");
iap_purchase_details(purchase_id, map);
if ds_map_find_value(map, "status") == iap_purchased
{
var product_id = ds_map_find_value(map, "product");
ds_map_replace(global.purchaseMap, product_id, 1);
switch(product_id)
{
case "iap_test3":
ads_disable(0);
break;
}
}
ds_map_destroy(map);
break;
}
ds_map_secure_save(global.purchaseMap, "iap_data.json");



***Left Pressed***

if iap_status() == iap_status_available
{
var product = "iap_test3";

if ds_map_find_value(global.purchaseMap, product) == 0
{
iap_acquire(product, "");
}
}
else
{
show_message_async("Store is not available.");
}


When I implement this code into my game and I press the button, I get an error saying "Store is not available", and I can't understand why! :(

Any help?
 
J

Jarrell Cobbs

Guest
Thank you
Check out the official GMS2 tutorials for IAP here and make sure you have everything as it is setup and explained:

https://help.yoyogames.com/hc/en-us/articles/360001971951-Android-Setting-Up-IAPs
Thank you for providing me with the tutorial! I followed the tutorial step-by-step and was able to get it working. However, after completing an in-app purchase through my app, the game crashes! And it continues to crash after trying to re-open the app! :( Any suggestions?
 
G

Guest

Guest
Thank you


Thank you for providing me with the tutorial! I followed the tutorial step-by-step and was able to get it working. However, after completing an in-app purchase through my app, the game crashes! And it continues to crash after trying to re-open the app! :( Any suggestions?
Do you get any errors? Have you tried in debug mode through VM-Android with a connected device?
 
J

Jarrell Cobbs

Guest
Ok so I figured out the problem. Apparently when the "iap_data.dat" file saves the information after purchase in the Async IAP Event, it makes the game crash and continue to crash after that. Also plugging in the Google Play Public Key in the Global Game Settings fixes it too! Here the working code for the Async IAP Event.

// Get the event type
var _id = iap_data[? "type"];
// Perform different code depending on the type
switch (_id)
{
case iap_ev_storeload: // Check to see if the store has loaded or not
if (iap_data[? "status"] == iap_storeload_ok)
{
show_debug_message("STORE LOADED");
}
else show_debug_message("STORE NOT LOADED");
break;
case iap_ev_product: // Get product details
var _product = iap_data[? "index"];
var _map = ds_map_create();
iap_product_details(_product, _map);
show_debug_message("PRODCT ACTIVATED - " + string(_product));
show_debug_message("ID - " + string(_map[? "id"]));
show_debug_message("Title - " + string(_map[? "title"]));
show_debug_message("Description - " + string(_map[? "description"]));
show_debug_message("Price - " + string(_map[? "price"]));
show_debug_message("Type - " + string(_map[? "type"]));
show_debug_message("Verified - " + string(_map[? "verified"]));
ds_map_destroy(_map);
break;
}
//case iap_ev_purchase:
var _product = iap_data[? "index"];
var _map = ds_map_create();
iap_purchase_details(_product, _map);
show_debug_message("PRODCT PURCHASED - " + string(_product));
show_debug_message("Product - " + string(_map[? "product"]));
show_debug_message("Order - " + string(_map[? "order"]));
show_debug_message("Token - " + string(_map[? "token"]));
show_debug_message("Payload - " + string(_map[? "payload"]));
show_debug_message("Receipt - " + string(_map[? "receipt"]));
show_debug_message("Response - " + string(_map[? "response"]));
switch (_map[? "status"])
{
case iap_available:
show_debug_message("iap_available");
break;
case iap_failed:
show_debug_message("iap_failed");
break;
case iap_purchased:
show_debug_message("iap_purchased");
if _map[? "product"] == product_consumable
{
show_debug_message("Consumable IAP Purchased");
iap_consume(product_consumable);
}
if _map[? "product"] == product_durable
{
show_debug_message("Durable IAP Purchased");
//global.savemap[? product_durable] = true;
//ds_map_secure_save(global.savemap, "iap_data.dat");
room_restart()
}
break;
case iap_canceled:
show_debug_message("iap_canceled");
break;
case iap_refunded:
show_debug_message("iap_refunded");
break;
}
ds_map_destroy(_map);
//break;


//case iap_ev_consume:
if iap_data[? "product"] == product_consumable
{
//global.savemap[? "consumed"] += 1000;
//ds_map_secure_save(global.savemap, "iap_data.dat");
}
//break;


As you can see, I put two forward slashes behind "global.savemap[? product_durable] = true;" and "ds_map_secure_save(global.savemap, "iap_data.dat");". In replacement of saving the purchase data. I placed an INI file in the code so at the start of the game, the code knows that the item was purchased:

show_debug_message("Durable IAP Purchased");
ini_open("purchase.ini")
ini_write_real("Variables", "Purchase", 1)
ini_close()
//global.savemap[? product_durable] = true;
//ds_map_secure_save(global.savemap, "iap_data.dat");
room_restart()

Thank you all for your help and cooperation in solving this problem it was much appreciated!! :)
 
G

GrandFree

Guest
Check out the official GMS2 tutorials for IAP here and make sure you have everything as it is setup and explained:

https://help.yoyogames.com/hc/en-us/articles/360001971951-Android-Setting-Up-IAPs
Hey Nocturne, none of the guides (including the one you've posted) cover refunds. However I'm certain there's a problem with the extension itself.

Basically users right now are able to purchase an IAP from Google Play, refund it, and then the extension will still think the IAP is considered purchased.

A status of iap_refunded never gets triggered. Any idea why?
 
Top