Android [PAID] Help troubleshooting IAPs

nick4508

Member
Hey guys,

My mobile game is finished and ready to be released, except for programmings in IAPs. I have followed this guide to set them up.

https://help.yoyogames.com/hc/en-us/articles/360031457831-Android-Google-Play-Billing-IAPs-

Unfortunately after months of trying, I cant for the life of me figure out why it isn't working.
They initiate correctly, are able to be purchased (I receive the receipt in an email) and respond to Google Play prompts. The issue is they do not actually reward the player with the item they have purchased. There are 10 different IAPS, all consumable.

Another problem is I do not know how to draw the price of the IAP in-game based off of each players region.

Here is the code I am using for the Async IAP event in my control object.
It is long, but is mostly a copy/paste job from the article, then modified for 10 IAPs and using my variables.

Code:
var _eventId = async_load[? "id"];
switch (_eventId)
    {
    case gpb_store_connect:
        // Store has connected so here you would generally add the products
        global.IAP_Enabled = true;
        GPBilling_AddProduct(global.IAP_PurchaseID[0]);
        GPBilling_AddProduct(global.IAP_PurchaseID[1]);
        GPBilling_AddProduct(global.IAP_PurchaseID[2]);
        GPBilling_AddProduct(global.IAP_PurchaseID[3]);
        GPBilling_AddProduct(global.IAP_PurchaseID[4]);
        GPBilling_AddProduct(global.IAP_PurchaseID[5]);
        GPBilling_AddProduct(global.IAP_PurchaseID[6]);
        GPBilling_AddProduct(global.IAP_PurchaseID[7]);
        GPBilling_AddProduct(global.IAP_PurchaseID[8]);
        GPBilling_AddProduct(global.IAP_PurchaseID[9]);

        GPBilling_QueryProducts();
        break;
    case gpb_store_connect_failed:
        // Store has failed to connect, so try again periodically
        alarm[0] = room_speed * 10;
        break;
    case gpb_product_data_response:
    // Retrieve the JSON object response string
    var _json = async_load[? "response_json"];
    var _map = json_decode(_json);
    // Check if the query was successful
    if _map[? "success"] == true
        {
        // Get the DS list of products and loop through them
        var _plist = _map[? "skuDetails"];
        for (var i = 0; i < ds_list_size(_plist); ++i;)
            {
            // The skuDetails key contains a DS list where
            // each list entry corresponds to a single
            // product in DS map form. This DS map can be parsed
            // to extract details like title, description and
            // price, as shown in the example, below:
            var _pmap = _plist[| i];
            var _num = 0;
            while(_pmap[? "productId"] != global.IAP_PurchaseID[_num])
                {
                ++_num;
                }
            global.IAP_ProductData[_num, 0] = _pmap[? "productId"];
            global.IAP_ProductData[_num, 1] = _pmap[? "price"];
            global.IAP_ProductData[_num, 2] = _pmap[? "title"];
            global.IAP_ProductData[_num, 3] = _pmap[? "decription"];
            }
        var _purchase_json = GPBilling_QueryPurchases(gpb_purchase_skutype_inapp);
        var _purchase_map = json_decode(_purchase_json);
        if _purchase_map[? "success"] == true
            {
            var _list = _purchase_map[? "purchases"];
            var _sz = ds_list_size(_list);
            for (var i = 0; i < _sz; ++i;)
                {
                var _map = _list[| i];
                if _map[? "purchaseState"] == 0
                    {
                    // Purchase has been made, so now get the product ID
                    // and unique "token" string to identify the purchase
                    var _pid = _map[? "productId"];
                    var _token = _map[? "purchaseToken"];
                    var _add = false;
                    // Check against existing purchase IDs
                    if _pid == global.IAP_PurchaseID[0]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[1]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[2]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[3]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[4]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[5]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[6]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[7]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[8]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    else if _pid == global.IAP_PurchaseID[9]
                        {
                        // It's a consumable purchase that hasn't been used yet
                        // so call the consume function on it:
                        GPBilling_ConsumeProduct(_token);
                        _add = true;
                        }
                    if _add
                        {
                        // add all purchase IDs and tokens into the relevant
                        // DS lists so they can be confirmed later
                        ds_list_add(global.CurrentTokens, _token);
                        ds_list_add(global.CurrentProducts, _pid);
                        }
                    }
                }
            }
        ds_map_destroy(_purchase_map);
        }
    ds_map_destroy(_map);
    break;
    case gpb_iap_receipt:
    // Get the JSON object response string
    var _json = async_load[? "response_json"];
    var _map = json_decode("response_json");
    // Check the response to see if it succeeded
    if _map[? "success"] == true
        {
        // Check the purchases key for any outstanding product purchases
        if ds_map_exists(_map, "purchases")
            {
            // Loop through the purchases list and parse each
            // entry to get the purchase data DS map
            var _plist = ds_map_find_value(_map, "purchases");
            for (var i = 0; i < ds_list_size(_plist);  ++i;)
                {
                var _pmap = _plist[| i];
                var _ptoken = _pmap[? "purchaseToken"];
                var _sig = GPBilling_Purchase_GetSignature(_ptoken);
                var _pjson = GPBilling_Purchase_GetOriginalJson(_ptoken);
                // Verify the purchase before consuming or acknowledging it
                if GPBilling_Purchase_VerifySignature(_pjson, _sig)
                    {
                    GPBilling_ConsumeProduct(_ptoken);
                    ds_list_add(global.CurrentTokens, _ptoken);
                    ds_list_add(global.CurrentProducts, _pmap[? "productId"]);
                    }
                }
            }
        }
    ds_map_destroy(_map);
    break;
    case gpb_product_consume_response:
    // Get the JSON object response string
    var _json = async_load[? "response_json"];
    var _map = json_decode(_json);
    var _num = -1;
    // Get the purchase token for the product that has been purchased
    if ds_map_exists(_map, "purchaseToken")
        {
        // compare the response purchase token against the list
        // of purchase token requests
        for (var i = 0; i < ds_list_size(global.CurrentTokens); ++i;)
            {
            // the response matches a token in the purchase check list
            if _map[? "purchaseToken"] == global.CurrentTokens[| i]
                {
                // Find out what product the token refers to
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[0]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_crystal += 10;
                    
                    event_perform_object(obj_menu_crystal_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[1]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_crystal += 21;
                    
                    event_perform_object(obj_menu_crystal_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[2]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_crystal += 44;
                    
                    event_perform_object(obj_menu_crystal_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[3]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_crystal += 115;
                    
                    event_perform_object(obj_menu_crystal_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[4]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_crystal += 240;
                    
                    event_perform_object(obj_menu_crystal_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[5]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_gold    += 500;
                    obj_var_store.inv_currency_crystal += 10;
                    obj_var_store.inv_currency_ability += 10;
                    obj_var_store.inv_currency_skill   += 10;
                    
                    event_perform_object(obj_menu_exclusives_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[6]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_craft_copper            += 50;
                    obj_var_store.inv_craft_tin                += 50;
                    obj_var_store.inv_craft_iron            += 50;
                    obj_var_store.inv_craft_bronze            += 20;
                    obj_var_store.inv_craft_silver            += 20;
                    obj_var_store.inv_craft_gold            += 20;
                    obj_var_store.inv_currency_blueprint    += 15;
                    obj_var_store.inv_enchant_alexandrite    += 1;
                    obj_var_store.inv_enchant_aventurine    += 1;
                    obj_var_store.inv_enchant_calcite        += 1;
                    obj_var_store.inv_enchant_citrine        += 1;
                    obj_var_store.inv_enchant_kyanite        += 1;
                    obj_var_store.inv_enchant_malacite        += 1;
                    obj_var_store.inv_enchant_marialite        += 1;
                    obj_var_store.inv_enchant_morganite        += 1;
                    obj_var_store.inv_enchant_nephrite        += 1;
                    obj_var_store.inv_enchant_onyx            += 1;
                    obj_var_store.inv_enchant_peridot        += 1;
                    obj_var_store.inv_enchant_pyrite        += 1;
                    obj_var_store.inv_enchant_rhodonite        += 1;
                    obj_var_store.inv_enchant_spinel        += 1;
                    obj_var_store.inv_enchant_stichtite     += 1;
                    obj_var_store.inv_enchant_tanzanite        += 1;
                    obj_var_store.inv_enchant_tourmaline    += 1;
                    obj_var_store.inv_enchant_zeolite        += 1;
                    
                    event_perform_object(obj_menu_exclusives_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[7]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_alch_achiote           += 3;
                    obj_var_store.inv_alch_amchur_powder   += 3;
                    obj_var_store.inv_alch_aqua_radish       += 3;
                    obj_var_store.inv_alch_blue_epazote       += 3;
                    obj_var_store.inv_alch_bluecrop           += 3;
                    obj_var_store.inv_alch_chorioactis       += 3;
                    obj_var_store.inv_alch_decayed_amanita += 3;
                    obj_var_store.inv_alch_dream_creeper   += 3;
                    obj_var_store.inv_alch_elderberry       += 3;
                    obj_var_store.inv_alch_ember_blossom   += 3;
                    obj_var_store.inv_alch_fenugreek       += 3;
                    obj_var_store.inv_alch_galangal_bunch  += 3;
                    obj_var_store.inv_alch_galangal_stem   += 3;
                    obj_var_store.inv_alch_mycena_leaf       += 3;
                    obj_var_store.inv_alch_perilla_bean       += 3;
                    obj_var_store.inv_alch_sangria_leaf       += 3;
                    obj_var_store.inv_alch_spiced_chervil  += 3;
                    obj_var_store.inv_alch_tundra_spice    += 3;
                    
                    event_perform_object(obj_menu_exclusives_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[8]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_skill   += 10;
                    obj_var_store.inv_currency_ability += 10;
                    
                    event_perform_object(obj_menu_exclusives_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                if global.CurrentProducts[| i] == global.IAP_PurchaseID[9]
                    {
                    // Assign a reward according to the product being purchased
                    obj_var_store.inv_currency_gold    += 500;
                    obj_var_store.inv_currency_crystal += 15;
                    obj_var_store.inv_currency_ability += 5;
                    obj_var_store.inv_currency_skill   += 5;
                    
                    event_perform_object(obj_menu_exclusives_buy,ev_user0,0);
                    
                    show_debug_message("SUCCESS - Purchase Made!");
                    
                    _num = i;
                    break;
                    }
                }
            }
        // Remove the purchased product and its purchase token
        // from the appropriate check lists
        if _num > -1
            {
            ds_list_delete(global.CurrentProducts, _num);
            ds_list_delete(global.CurrentTokens, _num);
            }
        }
    else
        {
        // Parse the error response codes here
        // and react appropriately
        }
    ds_map_destroy(_map);
    break;
    }

Another piece of relevant code from the tap event of an object which starts the purchase, however there doesn't appear to be any problems with this.

Code:
//Buys item
if (image_index = 0)
{
    //Chooses reward based off packages
    if (reward_type = 0)
    {
        if GPBilling_IsStoreConnected() && global.IAP_Enabled
        {
        var _chk = GPBilling_PurchaseProduct(global.IAP_PurchaseID[0]);
        if _chk != gpb_no_error
            {
            show_debug_message("ERROR - Purchase Not Made");
            }
            else
            {
            show_debug_message("SUCCESS - Purchase Started");   
            }
        }
        else
        {
        show_debug_message("ERROR - IAP Not Enabled");   
        }
    }
    
    if (reward_type = 1)
    {
        if GPBilling_IsStoreConnected() && global.IAP_Enabled
        {
        var _chk = GPBilling_PurchaseProduct(global.IAP_PurchaseID[1]);
        if _chk != gpb_no_error
            {
            show_debug_message("ERROR - Purchase Not Made");
            }
            else
            {
            show_debug_message("SUCCESS - Purchase Started");   
            }
        }
        else
        {
        show_debug_message("ERROR - IAP Not Enabled");   
        }
    }
    
    if (reward_type = 2)
    {
        if GPBilling_IsStoreConnected() && global.IAP_Enabled
        {
        var _chk = GPBilling_PurchaseProduct(global.IAP_PurchaseID[2]);
        if _chk != gpb_no_error
            {
            show_debug_message("ERROR - Purchase Not Made");
            }
            else
            {
            show_debug_message("SUCCESS - Purchase Started");   
            }
        }
        else
        {
        show_debug_message("ERROR - IAP Not Enabled");   
        }
    }
    
    if (reward_type = 3)
    {
        if GPBilling_IsStoreConnected() && global.IAP_Enabled
        {
        var _chk = GPBilling_PurchaseProduct(global.IAP_PurchaseID[3]);
        if _chk != gpb_no_error
            {
            show_debug_message("ERROR - Purchase Not Made");
            }
            else
            {
            show_debug_message("SUCCESS - Purchase Started");   
            }
        }
        else
        {
        show_debug_message("ERROR - IAP Not Enabled");   
        }
    }
    
    if (reward_type = 4)
    {
        if GPBilling_IsStoreConnected() && global.IAP_Enabled
        {
        var _chk = GPBilling_PurchaseProduct(global.IAP_PurchaseID[4]);
        if _chk != gpb_no_error
            {
            show_debug_message("ERROR - Purchase Not Made");
            }
            else
            {
            show_debug_message("SUCCESS - Purchase Started");   
            }
        }
        else
        {
        show_debug_message("ERROR - IAP Not Enabled");   
        }
    }
}

Thanks for taking the time to read this, if you are able to help me with IAPs and showing prices in-game, I am willing to pay.

Also if you are seriously interested I have a YYZ file of just the games main menu containing the IAP objects, which may assist you.
 
Top