• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

iOS New INAPP extension problem

Hello! I tried to implement the new inapp ext but encountered a problem. When I try to call validate receipt it always fails. I also found that in the pdf manual verification function requires parameter (the receipt itself) and in the real ext it doesnt.
Is there a demo project where I can find the correct way for implementing inapps?
Any help is appretiated.
 
And one more thing. ios_iap_QueryPurchases() is restoring all old purchases automatically. Is it supposed to work like this. I'm 100% sure that on IOS autorestoring of purchases is prohibited.
 
The iOS article was updated around 10 hours ago, perhaps that solves your issue?
No. Nothing really changed in that update.
Please if anyone can explain that code:

var _receipt = ios_iap_GetReceipt();
// CALL SERVER CHECK WITH RECEIPT HERE
// or validate, award the product, and finalise, as shown below
if ios_iap_ValidateReceipt(_receipt) == true // <------------- THIS ARGUMENT IS NOT REQUIRED!!!!!!! BUT STILL IS IN THE CODE!.

Please check the code above. Validation keeps failing for me though I dont provide any arguments. Coz this func doesnt want it.
Besides that in the provided example the validation is performed for every purchase registered but I dont really understand why. If it validates the same receipt every time(coz the GetReceipt funct doesnt accept any params so returns same receipt every time). This part is very weird to me. Please help anyone! @Dan maybe?

And also when Im doing QueryPurchases on a first run it restores the old purchases made a year ago. How can I avoid this?
Hey guys am I the only one who is using the
ios inapps here?
 
Last edited:

chirpy

Member
ios_iap_ValidateReceipt indeed does not take any receipt argument. Simply removing the argument does the trick. From what I saw from the implementation .mm file, ios_iap_GetReceipt almost does nothing, and returns a string for users to apply custom validation only.

I had tested yesterday without ios_iap_GetReceipt, and my sandbox testing works.

=====
My app got rejected somehow though; the review team claimed that my IAP button did not respond. :'( Still looking into it.

[Edit: I realized that I did not reconnect and reset the IAP available flag after os_is_network_connected status changed.]
 
Last edited:
ios_iap_ValidateReceipt indeed does not take any receipt argument. Simply removing the argument does the trick. From what I saw from the implementation .mm file, ios_iap_GetReceipt almost does nothing, and returns a string for users to apply custom validation only.

I had tested yesterday without ios_iap_GetReceipt, and my sandbox testing works.

=====
My app got rejected somehow though; the review team claimed that my IAP button did not respond. :'( Still looking into it.

[Edit: I realized that I did not reconnect and reset the IAP available flag after os_is_network_connected status changed.]
Could you please be so kind to share your code. I believe asynchronous iap event would be enough. Or more at your will.
 

chirpy

Member
First I AddProduct and QueryProducts on init. I'm adding code to check network state now.
I basically only have ad removal, so here I remove ads at any purchase before finishing transaction.

ios_iap_QueryPurchases is called on async ios_product_update, which is callback from QueryProducts.

Code:
#region Apple iOS IAP
    switch (_id)
    {
        case ios_product_update:
            var _json = async_load[? "response_json"]; // This is only to retrieve price information etc for display purposes
            show_debug_message("ios_iap_QueryProducts:::::\n" + _json);
         
            _json = ios_iap_QueryPurchases();
            show_debug_message("ios_iap_QueryPurchases:::::\n" + _json);
            break;
     
        case ios_payment_queue_update:
            var _json = async_load[? "response_json"];
            show_debug_message("ios_payment_queue_update:::::\n" + _json);
         
            if (_json != "")
            {
                var _map = json_decode(_json);
                var _plist = _map[? "purchases"];
                var _sz = ds_list_size(_plist);
                // loop through purchases
                for (var i = 0; i < _sz; ++i)
                {
                    var _pmap = _plist[| i];
                 
                    // Check purchases
                    var _ptoken = _pmap[? "purchaseToken"];
                    var _pstate = _pmap[? "purchaseState"];
                    if (_pstate != ios_purchase_failed) // ios_purchase_restored / ios_purchase_success
                    {
                        //var _receipt = ios_iap_GetReceipt();
                        // CALL SERVER CHECK WITH RECEIPT HERE
                        // or validate, finalise and award the product
                        if (ios_iap_ValidateReceipt() == true)
                        {
                            show_debug_message("ios_iap_ValidateReceipt:::::ok::ios_iap_FinishTransaction");
                            //
                            /////// I basically only have ad removal, so here I remove ads at any purchase before finish transaction
                            //
                            ios_iap_FinishTransaction(_ptoken);
                        }
                        else
                        {    // Validation failed, so deal with it here
                            show_debug_message("ios_iap_ValidateReceipt:::::failed::ios_iap_RefreshReceipt");
                            ios_iap_RefreshReceipt(); // should probably validate again; I dunno
                        }
                    }
                    else
                    {
                        // Purchase failed, so finalise it.
                        show_debug_message("ios_purchase_failed:::::ios_iap_FinishTransaction");
                        ios_iap_FinishTransaction(_ptoken);
                    }
                 
                    show_debug_message("======\n" + json_encode(_pmap) + "\n======");
                }
                ds_map_destroy(_map);
            }
            break;
    }
    #endregion
 
Last edited:
First I AddProduct and QueryProducts on init. I'm adding code to check network state now.
I basically only have ad removal, so here I remove ads at any purchase before finishing transaction.

ios_iap_QueryPurchases is called on async ios_product_update, which is callback from QueryProducts.

Code:
#region Apple iOS IAP
    switch (_id)
    {
        case ios_product_update:
            var _json = async_load[? "response_json"]; // This is only to retrieve price information etc for display purposes
            show_debug_message("ios_iap_QueryProducts:::::\n" + _json);
        
            _json = ios_iap_QueryPurchases();
            show_debug_message("ios_iap_QueryPurchases:::::\n" + _json);
            break;
    
        case ios_payment_queue_update:
            var _json = async_load[? "response_json"];
            show_debug_message("ios_payment_queue_update:::::\n" + _json);
        
            if (_json != "")
            {
                var _map = json_decode(_json);
                var _plist = _map[? "purchases"];
                var _sz = ds_list_size(_plist);
                // loop through purchases
                for (var i = 0; i < _sz; ++i)
                {
                    var _pmap = _plist[| i];
                
                    // Check purchases
                    var _ptoken = _pmap[? "purchaseToken"];
                    var _pstate = _pmap[? "purchaseState"];
                    if (_pstate != ios_purchase_failed) // ios_purchase_restored / ios_purchase_success
                    {
                        //var _receipt = ios_iap_GetReceipt();
                        // CALL SERVER CHECK WITH RECEIPT HERE
                        // or validate, finalise and award the product
                        if (ios_iap_ValidateReceipt() == true)
                        {
                            show_debug_message("ios_iap_ValidateReceipt:::::ok::ios_iap_FinishTransaction");
                            //
                            /////// I basically only have ad removal, so here I remove ads at any purchase before finish transaction
                            //
                            ios_iap_FinishTransaction(_ptoken);
                        }
                        else
                        {    // Validation failed, so deal with it here
                            show_debug_message("ios_iap_ValidateReceipt:::::failed::ios_iap_RefreshReceipt");
                            ios_iap_RefreshReceipt(); // should probably validate again; I dunno
                        }
                    }
                    else
                    {
                        // Purchase failed, so finalise it.
                        show_debug_message("ios_purchase_failed:::::ios_iap_FinishTransaction");
                        ios_iap_FinishTransaction(_ptoken);
                    }
                
                    show_debug_message("======\n" + json_encode(_pmap) + "\n======");
                }
                ds_map_destroy(_map);
            }
            break;
    }
    #endregion
Im doing exatly the same but the validation always fail :( Still there is a problem with autorestoring old purchases. Ive made up a fix but still wandering why this is not fixet by yoyo stuff yet.
 

clee2005

Member
No. Nothing really changed in that update.
Please if anyone can explain that code:

var _receipt = ios_iap_GetReceipt();
// CALL SERVER CHECK WITH RECEIPT HERE
// or validate, award the product, and finalise, as shown below
if ios_iap_ValidateReceipt(_receipt) == true // <------------- THIS ARGUMENT IS NOT REQUIRED!!!!!!! BUT STILL IS IN THE CODE!.

Please check the code above. Validation keeps failing for me though I dont provide any arguments. Coz this func doesnt want it.
Besides that in the provided example the validation is performed for every purchase registered but I dont really understand why. If it validates the same receipt every time(coz the GetReceipt funct doesnt accept any params so returns same receipt every time). This part is very weird to me. Please help anyone! @Dan maybe?

And also when Im doing QueryPurchases on a first run it restores the old purchases made a year ago. How can I avoid this?
Hey guys am I the only one who is using the
ios inapps here?
I posted about this here : https://forum.yoyogames.com/index.php?threads/gms2-version-2-2-4-full-release.68163/page-2#post-407249

As @chirpy mentioned, just remove the _receipt param. It's not needed. I've tested it and got it all working like this.
 

chirpy

Member
I was quite very wrong about ios_product_update serving only display purposes..
Not properly waiting for the async product info made my IAP fail in app review environment.
Please don't follow my bad practice if anyone did even try. :-\

Code:
        case ios_product_update:
            var _json = async_load[? "response_json"]; // This is only to retrieve price information etc for display purposes <---- NO! PurchaseProduct can only be called after product info had been returned
            show_debug_message("ios_iap_QueryProducts:::::\n" + _json);
        
            _json = ios_iap_QueryPurchases();
            show_debug_message("ios_iap_QueryPurchases:::::\n" + _json);
            break;
=================

@booksmaster
I don't get what you meant about auto-restoring purchases. Payment queue is supposedly updated only after a PurchaseProduct call or RestorePurchase call; neither are automatic, no? I was able to sandbox test purchases, and then delete my app to sandbox test purchase again. So long as I didn't hit my RestorePurchase button, the app looks like nothing was purchased. Also, where did you see the guideline about iOS forbidding auto-restoring purchases?
 
@booksmaster
I don't get what you meant about auto-restoring purchases. Payment queue is supposedly updated only after a PurchaseProduct call or RestorePurchase call; neither are automatic, no? I was able to sandbox test purchases, and then delete my app to sandbox test purchase again. So long as I didn't hit my RestorePurchase button, the app looks like nothing was purchased. Also, where did you see the guideline about iOS forbidding auto-restoring purchases?
My app has updated and some new inapp options are present now. So when I call QueryPurchases it must not restore something that was bought not during current install. Like the old purchases I had in previous builds. But the old ones must be restored only after I call RestoreAll(or why else would I want to press that button).
I dont really have a link to the guidelines but here is the link on unity forum where people encountered same problem. https://forum.unity.com/threads/inapp-auto-restore.536966/
For now Ive managed to make a clumsy fix but was hoping this would be fixed in the future updates.
 
I'm facing the same issue, using the latest IDE and tried almost everything. Validation just fails all the time...

For now Ive managed to make a clumsy fix but was hoping this would be fixed in the future updates.
Are you able to share that fix, we are really f****d up with that issue.
 
Last edited:
Top