• 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!
  • 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.

Discussion iOS & Android: Confirm IAP through IAP Async Events

P

Panagis Alisandratos

Guest
Has anyone here confirmed, without having stored the proof-of-purchase in a file (i.e. purely through IAP functions and/or asynchronous events), that a user had previously performed an in-app purchase?

The In App Purchases page of the manual states:
You should also be aware that GameMaker Studio 2 does not persist active purchase state across multiple plays of the game (and thus iap_is_purchased() is unreliable if a store has not successfully loaded). This means that you will have to store this information yourself and retrieve it again on each start-up of your game.
However, iap_is_purchased was deprecated in GMS 1.4 and is no longer available in GMS 2.

Confirming a purchase across multiple plays by checking with the store itself (rather than a local file) should be possible and, as far as I can tell, is the most secure way of doing so. Another secure, albeit involved, alternative would be to encrypt the file containing the proof-of-purchase by sending its contents over to a server which does the encryption; that way, encryption keys will never be stored on a user's device. And yet another alternative would be to write an extension that restores the functionality of iap_is_purchased.
 

rIKmAN

Member
Has anyone here confirmed, without having stored the proof-of-purchase in a file (i.e. purely through IAP functions and/or asynchronous events), that a user had previously performed an in-app purchase?

The In App Purchases page of the manual states:

However, iap_is_purchased was deprecated in GMS 1.4 and is no longer available in GMS 2.

Confirming a purchase across multiple plays by checking with the store itself (rather than a local file) should be possible and, as far as I can tell, is the most secure way of doing so. Another secure, albeit involved, alternative would be to encrypt the file containing the proof-of-purchase by sending its contents over to a server which does the encryption; that way, encryption keys will never be stored on a user's device. And yet another alternative would be to write an extension that restores the functionality of iap_is_purchased.
Doesn't iap_restore_all do what you asking?
Restores all purchases to their default status for the game and user. This would be applicable if (for example) the user has changed device or removed the title from their current device and has re-installed the title. This will trigger an IAP Event, of the type iap_ev_restore, and the ds_map iap_data will have the following extra key which can then be checked to make sure that the products and purchases have been successfully restored:

  • "result" - The result as a boolean value, where true indicates a successful restore and false some kind of error.
NOTE: Only the Mac and iOS stores currently provide restore functionality.


Example:
Code:
iap_restore_all();
This would request that the target store restores all purchases for the game on the device running it, and it will trigger an IAP Event with the result of the call stored in the special iap_data ds_map.
 
P

Panagis Alisandratos

Guest
iap_restore_all can be considered another solution, yes, but it is primarily intended for when users change devices and it will not work on Android.
 
P

Panagis Alisandratos

Guest
I didn't mention iOS either, but I did include a "mobile" tag. It's a pity tags are so tiny. I'll update the post.
 

rIKmAN

Member
I didn't mention iOS either, but I did include a "mobile" tag. It's a pity tags are so tiny. I'll update the post.
Well "IAP" generally implies both mobile targets so I tried to help solve half your problem - unfortunately it was the half I was meant to guess that you weren't talking about.
 
P

Panagis Alisandratos

Guest
I'm currently conducting iOS sandbox testing of IAPs and it appears that iap_activate is all you need. The manual states that "Activating purchases will also trigger an IAP Event, which creates a special iap_data ds_map of the event type iap_ev_product", but it appears to trigger an event with the type iap_ev_purchase as well, where you can check the purchase status.

Up next: Android.
 

sman

Member
@Nocturne, I tried to do what you said (on Android):
- iap_enumerate_products works: it gets me one product ID (but I don't really need that because I already know the ID of the product I'm selling)
- but all the values I get with iap_purchase_details (status, product, token, ...) are "undefined" :(

@Panagis Alisandratos, have you found a solution for Andoid?
EDIT: your solution works for Android! Great! So the purchase map of that tutorial is useless?
 
Last edited:
P

Panagis Alisandratos

Guest
Woohoo, glad you got it working on Android; I wasn't going to get around to that until maybe a month from now. The point of the purchase map is for persisting purchase history between playthroughs so that they can be verified if/when the user launches the app while offline. So while I wouldn't say it's a useless part of the tutorial, it serves no purpose if your app will always require a connection to a target store for purchase-verification purposes. I'm not certain of the likelihood of the file being tampered with by the user, but I'd rather not take any chances.
 

sman

Member
I bought an in-app product then went offline and restarted the game. I still could read the purchase status and verified I owned the product.
So it seems to work offline. So for now I do not plan to use a purchase map.

EDIT: Well, it was only working because I was still connected to google play but I really need a purchase map for when I'm not.
 
Last edited:

Slyddar

Member
EDIT: your solution works for Android! Great!
sman, would you mind elaborating on how you got the restore to work on Android please? I only have one purchase, a "noads" product, which is working, but am trying to work out how to do a restore button.

Do I need to do anything to retrieve more information as I'm already running an "Async - In-App Purchase" event with this code at game start, along with the iap_activate code. I just can't get my head around how to link the restore to what I already have. Does this single call at game start contain the restore information if a purchased user has installed the app on a new device, or does it need to be run again when the restore button is pressed?

Async - In-App Purchase Event
Code:
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 "noads":
               lite_version = false;
               //save
               ds_map_secure_save(global.purchaseMap, "iap_data.json");
            break;
            }
         }
      ds_map_destroy(map);
      break;
   }
What makes this difficult is the time it takes to test, considering you have to upload the game every time you make a code change just to test it. Any other hints would be appreciated.
 

sman

Member
@TheSly, my code is almost like yours except I don't use a purchase map.
At game start I call iap_activate and then that code is executed and lite_version is set to true or false. It doesn't work for you?
Me I don't have to upload my game. I just launch it with F5.
 

Slyddar

Member
I was under the impression I needed to also make a "Restore" button the user could use to restore the purchase. I just created a new test user on my phone, a user that had previously test purchased the game on an account in Bluestacks. Logging in and installing it, shows the game is already unlocked. So maybe I'm over thinking it, and what I have is all I need to make it work.

Well I'll go work on the IOS side and see how that pans out. Thanks for the quick reply.
 
Top