A feature that has been requested a lot for GameMaker: Studio is the ability to use Local and Remote push notifications to notify users of special events, promotions, etc... when your game is not actively being played. This feature has been added in the 1.3 update to GameMaker: Studio and is initially available for the iOS and Android target platforms.
What Are Push Notifications?
On mobile devices, normally only one application can be active in the foreground at any time, but many games and applications operate in a time-based or interconnected environment where events of interest to users can occur when the application is not in the foreground. In these cases, Local and Remote push notifications can allow games to notify their users when the events occur, and also permit the user to start the game from the notification.
These notifications will appear as an icon and a short message at the top of the main screen on the device, and you can use them to promote a special offer, announce updates to your game, or simply invite the user to come and play again if they haven't for a while. However, before you rush off to add these into your game, it's worth noting that many users do not like these notifications, and so you should consider making them an "opt-in/out" feature from the options within your game.
How Do They Work?
When the operating system delivers a local or remote push notification and the target application is not running in the foreground, it presents the notification to the user in the form of a banner. If there is a notification alert and the user taps on it, then the game is launched and an Asynchronous Push Event is called where you can check the callback string that you specify and resolve the push based on its value. If the application is running in the foreground when the notification is delivered, the application will still receive an Asynchronous Push Event, but the user will get no message displayed unless you create it yourself.
There are a few differences to note between supported platforms:
- On Android, all notifications received when the app is not running/in the background, will be stored, and the data delivered by the async event the next time the app runs.
- On iOS, data for a particular notification will only be delivered when the notification is selected (or if the app is running in foreground when the notification is received).
Local Notifications
A local push notification is local to the device that the game is installed on, and requires no backend server. You simply set the date and time for the notification and it will be displayed to the user if the game is not currently running. This type of notification is useful to set "reminders" for the user to play your game again, or to offer a daily reward for playing, etc... and when the user taps the notification it will launch the game and pass in a data string which can then be parsed by the game to give a reward or whatever.
NOTE: This function is limited to the iOS and Android target modules.
The function for sending a push notification requires that you give it a fire time, a title, a message and "payload" data in the form of a string. The notification will be fired off when the given time is reached, and if the user taps it, then your game will be started and the payload string sent to the Asynchronous Push event where it can be parsed. the actual code would look something like this:
var fireTime = date_inc_day(date_current_datetime(), 1);
var data = "daily_reward";
push_local_notification(fireTime, "Ahoy!", "Catch The Haggis Has A Present", data);
Remote Notifications
Remote notification messages are independant of your game and are sent by a server to a service provided by the device platform App Store. This then forwards those messages onto all the devices onto which your application has been installed. There are no functions in GameMaker: Studio to deal with remote notifications, as they must all be generated by your server and handled by the respective App Stores. However, once set up correctly, GameMaker: Studio games will receive these notifications, which can then be dealt with in the Asynchronous Push Event, as you would a local notification.
For all available platforms, once you have done the necessary set-up, when the game is run on a device it will register that device with the platforms push notification service. This will trigger an Asynchronous Push Notification Event, and the generated ds_map will have a key "type" which will have the value "register" as well as a new key, "reg_id", containing the registration id (or an error message in the "error" key, if "status" is 0). You must then send this registration id to your server (every device that your game is installed on will have a different registration id). Your server must maintain a list of ids for registered devices, as when when you send a push notification message from your server, you use the registration ids to send the message to those devices.
It is worth noting note that there is no guarantee that remote push notifications will be delivered, and that the allowed data payload is fairly small. The actual size of the payload data varies between platforms, but iOS is particularly limited - the Apple service only delivers the most recent notification, which must be selected by the recipient for the payload data to be delivered to your async event, and these notifications have a maximum payload size of 256bytes. Typically a remote push notification would just indicate that new data is available from your server for example.
For further details on how to go about setting up a server, as well as information specific to the available platforms, please see the following pages on the YoYo Games Knowledge Base:
The Asynchronous Push Event
The Push Notification Event is one that is triggered by the call back from push notifications on the device OS, either from a local source using the function push_local_notification, or from a remote source (ie: your server). It generates a ds_map that is exclusive to this event and is stored in the special variable async_load. This ds_map always has the following keys:
"type": Value can be "local" for a device local notification, "remote" for a remote notification, or "register" for remote notification registration.
"status": Value will be "1" for success or "0" for an error.
There may be additional key entries based on the "type" returned and the "status" value. For "status", if an error has been returned ("0"), then you will also have the following key:
"error": Contains details of the error received.
If the "status" value is 0 (ie: no errors) then the ds_map will contain the following additional values, depending on the value of the "type" key:
"reg_id": If the "type" received was "register", then this key will hold the device registration id for remote notifications.
"data": If the "type" received was "local" or "remote", then this key will hold the string payload that you defined when you called the notification function.
When you write your code for parsing the call back data, the general workflow is exactly the same for both local and remote notifications. Let's use the example code we posted earlier to illustrate how you would do this:
var fireTime = date_inc_day(date_current_datetime(), 1);
var data = "daily_reward";
push_local_notification(fireTime, "Ahoy!", "Catch The Haggis Has A Present", data);
This will set a timer to "push" a notification to the device when one day has passed. When the day is up, if your game is either in the background or not running, a notification will be shown to the user with the given title and message (on iOS, the game name is shown and the title is ignored), and then an asynchronous Push Notification Event will be called. Note that if the game is in the foreground when the time for the notification comes, it will not be shown, but the asynchronous event will still trigger. In the event itself you would handle the callback something like this:
var type = ds_map_find_value(async_load, "type");
var status = ds_map_find_value(async_load, "status");
if status == 0
{
//error of some kind
var error = ds_map_find_value(async_load, "error");
show_debug_message("error=" + string(error));
}
else
{
if type == "register"
{
global.reg_id = ds_map_find_value(async_load, "reg_id");
}
else
{
var data = ds_map_find_value(async_load, "data");
if data == "daily_reward"
{
global.Gold += 1000;
}
}
}
And that's it for Push notifications! Simple to set up but potentially very rewarding for both the developer and the end user, as long as you are careful not to abuse the system.