B
Blakecubed
Guest
Hello!
I have followed the official Gamemaker tutorial on In-App purchases, and made some tweaks because it crashed the game, and have gotten it to the point in which I can tap on a purchase button. However, iap_activate does not seem to work correctly, leading the game to return an iap_failed state every time. My device is connected to the Store and should be running a Sandbox account. I also made sure to click "Create Executable".
Here is the code:
<Create Event>
/// Load IAP
// Store the product names in variables for easy editing
product_pack1 = "(omitted but should be valid)";
product_pack2 = "(omitted but should be valid)";
product_pack3 = "(omitted but should be valid)";
var map_create = true; // This is to tell us if we need to create the save map
if (file_exists("iap_data.dat")) // Check for the file
{
// The file exists so load the save map
global.savemap= ds_map_secure_load("iap_data.dat");
// Check the map has been loaded correctly
if (ds_exists(global.savemap, ds_type_map))
{
map_create = false;
// Check to see if the non-consumable IAP has been used
if (ds_map_exists(global.savemap, product_pack1))
{
if (ds_map_find_value(global.savemap, product_pack1) == false)
{
// The non-consumable IAP has not been used so do something
// like enable ads, or disable extra content, etc...
}
}
}
}
// The save map doesn't exist, so create it and initialise the IAPs to false
if (map_create)
{
global.savemap= ds_map_create();
//ds_map_add(global.savemap, product_pack1, false);
//ds_map_add(global.savemap, "consumed", 0);
ds_map_secure_save(global.savemap, "iap_data.dat");
}
var productList = ds_list_create();
// Create non-consumable iap
//ds_map_add(durable_map , "id", product_durable);
//ds_map_add(durable_map , "title", "Test Durable");
//ds_map_add(durable_map , "type", "Durable");
//ds_list_add(productList, durable_map);
// Create consumable IAP
var product_map1 = ds_map_create();
ds_map_add(product_map1, "id", product_pack1);
ds_map_add(product_map1, "title", "Continue Pack 1");
ds_map_add(product_map1, "description", "Receive 75 Continues!");
ds_map_add(product_map1, "price", "$0.99");
ds_map_add(product_map1, "type", "Consumable");
var product_map2 = ds_map_create();
ds_map_add(product_map2, "id", product_pack2);
ds_map_add(product_map2, "title", "Continue Pack 2");
ds_map_add(product_map2, "description", "Receive 300 Continues!");
ds_map_add(product_map2, "price", "$2.99");
ds_map_add(product_map2, "type", "Consumable");
var product_map3 = ds_map_create();
ds_map_add(product_map3, "id", product_pack3);
ds_map_add(product_map3, "title", "Continue Pack 3");
ds_map_add(product_map3, "description", "Receive 600 Continues!");
ds_map_add(product_map3, "price", "$4.99");
ds_map_add(product_map3, "type", "Consumable");
ds_list_add(productList, product_map1);
ds_list_add(productList, product_map2);
ds_list_add(productList, product_map3);
// Activate IAP
iap_activate(productList);
// Clean up
//ds_map_destroy(durable_map);
ds_map_destroy(product_map1);
ds_map_destroy(product_map2);
ds_map_destroy(product_map3);
ds_list_destroy(productList);
< 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_message_async("PRODCT ACTIVATED - " + string(_product));
show_message_async("ID - " + string(_map[? "id"]));
show_message_async("Title - " + string(_map[? "title"]));
show_message_async("Description - " + string(_map[? "description"]));
show_message_async("Price - " + string(_map[? "price"]));
ds_map_destroy(_map);
break;
case iap_ev_purchase:
var _product = iap_data[? "index"];
var _map = ds_map_create();
iap_purchase_details(_product, _map);
if (_map[? "verified"])
{
show_message_async("TRUE");
}
else
{
show_message_async("FALSE");
}
switch (_map[? "status"])
{
case iap_available:
show_message_async("iap_available");
break;
case iap_failed:
show_message_async("iap_failed");
break;
case iap_purchased:
show_message_async("iap_purchased");
if _map[? "product"] == product_pack1
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack1);
}
if _map[? "product"] == product_pack2
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack2);
}
if _map[? "product"] == product_pack3
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack3);
}
break;
case iap_canceled:
show_message_async("iap_canceled");
break;
case iap_refunded:
show_message_async("iap_refunded");
break;
}
ds_map_destroy(_map);
break;
case iap_ev_consume:
if iap_data[? "product"] == product_pack1
{
global.savemap[? "consumed"] += 75;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
if iap_data[? "product"] == product_pack2
{
global.savemap[? "consumed"] += 300;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
if iap_data[? "product"] == product_pack3
{
global.savemap[? "consumed"] += 600;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
break;
case iap_ev_restore:
if iap_data[? "result"]
{
show_message_async("Purchases restored!");
}
else
{
show_message_async("Purchases were not able to be restored.");
}
break;
}
Any help would be greatly appreciated!
Thanks,
Blakecubed
PS We're not abusing IAP functionality, don't worry
I have followed the official Gamemaker tutorial on In-App purchases, and made some tweaks because it crashed the game, and have gotten it to the point in which I can tap on a purchase button. However, iap_activate does not seem to work correctly, leading the game to return an iap_failed state every time. My device is connected to the Store and should be running a Sandbox account. I also made sure to click "Create Executable".
Here is the code:
<Create Event>
/// Load IAP
// Store the product names in variables for easy editing
product_pack1 = "(omitted but should be valid)";
product_pack2 = "(omitted but should be valid)";
product_pack3 = "(omitted but should be valid)";
var map_create = true; // This is to tell us if we need to create the save map
if (file_exists("iap_data.dat")) // Check for the file
{
// The file exists so load the save map
global.savemap= ds_map_secure_load("iap_data.dat");
// Check the map has been loaded correctly
if (ds_exists(global.savemap, ds_type_map))
{
map_create = false;
// Check to see if the non-consumable IAP has been used
if (ds_map_exists(global.savemap, product_pack1))
{
if (ds_map_find_value(global.savemap, product_pack1) == false)
{
// The non-consumable IAP has not been used so do something
// like enable ads, or disable extra content, etc...
}
}
}
}
// The save map doesn't exist, so create it and initialise the IAPs to false
if (map_create)
{
global.savemap= ds_map_create();
//ds_map_add(global.savemap, product_pack1, false);
//ds_map_add(global.savemap, "consumed", 0);
ds_map_secure_save(global.savemap, "iap_data.dat");
}
var productList = ds_list_create();
// Create non-consumable iap
//ds_map_add(durable_map , "id", product_durable);
//ds_map_add(durable_map , "title", "Test Durable");
//ds_map_add(durable_map , "type", "Durable");
//ds_list_add(productList, durable_map);
// Create consumable IAP
var product_map1 = ds_map_create();
ds_map_add(product_map1, "id", product_pack1);
ds_map_add(product_map1, "title", "Continue Pack 1");
ds_map_add(product_map1, "description", "Receive 75 Continues!");
ds_map_add(product_map1, "price", "$0.99");
ds_map_add(product_map1, "type", "Consumable");
var product_map2 = ds_map_create();
ds_map_add(product_map2, "id", product_pack2);
ds_map_add(product_map2, "title", "Continue Pack 2");
ds_map_add(product_map2, "description", "Receive 300 Continues!");
ds_map_add(product_map2, "price", "$2.99");
ds_map_add(product_map2, "type", "Consumable");
var product_map3 = ds_map_create();
ds_map_add(product_map3, "id", product_pack3);
ds_map_add(product_map3, "title", "Continue Pack 3");
ds_map_add(product_map3, "description", "Receive 600 Continues!");
ds_map_add(product_map3, "price", "$4.99");
ds_map_add(product_map3, "type", "Consumable");
ds_list_add(productList, product_map1);
ds_list_add(productList, product_map2);
ds_list_add(productList, product_map3);
// Activate IAP
iap_activate(productList);
// Clean up
//ds_map_destroy(durable_map);
ds_map_destroy(product_map1);
ds_map_destroy(product_map2);
ds_map_destroy(product_map3);
ds_list_destroy(productList);
< 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_message_async("PRODCT ACTIVATED - " + string(_product));
show_message_async("ID - " + string(_map[? "id"]));
show_message_async("Title - " + string(_map[? "title"]));
show_message_async("Description - " + string(_map[? "description"]));
show_message_async("Price - " + string(_map[? "price"]));
ds_map_destroy(_map);
break;
case iap_ev_purchase:
var _product = iap_data[? "index"];
var _map = ds_map_create();
iap_purchase_details(_product, _map);
if (_map[? "verified"])
{
show_message_async("TRUE");
}
else
{
show_message_async("FALSE");
}
switch (_map[? "status"])
{
case iap_available:
show_message_async("iap_available");
break;
case iap_failed:
show_message_async("iap_failed");
break;
case iap_purchased:
show_message_async("iap_purchased");
if _map[? "product"] == product_pack1
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack1);
}
if _map[? "product"] == product_pack2
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack2);
}
if _map[? "product"] == product_pack3
{
show_message("Consumable IAP Purchased");
iap_consume(product_pack3);
}
break;
case iap_canceled:
show_message_async("iap_canceled");
break;
case iap_refunded:
show_message_async("iap_refunded");
break;
}
ds_map_destroy(_map);
break;
case iap_ev_consume:
if iap_data[? "product"] == product_pack1
{
global.savemap[? "consumed"] += 75;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
if iap_data[? "product"] == product_pack2
{
global.savemap[? "consumed"] += 300;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
if iap_data[? "product"] == product_pack3
{
global.savemap[? "consumed"] += 600;
ds_map_secure_save(global.savemap, "iap_data.dat");
}
break;
case iap_ev_restore:
if iap_data[? "result"]
{
show_message_async("Purchases restored!");
}
else
{
show_message_async("Purchases were not able to be restored.");
}
break;
}
Any help would be greatly appreciated!
Thanks,
Blakecubed
PS We're not abusing IAP functionality, don't worry