Skip to main content

Push notifications SDK for Godot Engine (version 1.4.0)

Prerequisites

Push notification terms and conditions:

  • The current version of RuStore is installed on the user's device.
  • RuStore app supports push notifications.
  • The RuStore app is allowed to run in the background.
  • User is authorized in RuStore.
  • The signature fingerprint of the app must match the fingerprint added to the RuStore Console.
  • Godot 4 and later.

Implementation example

Checkout example app to learn how to implement push notification SDK.

Connecting to project

  1. Copy the plugin project and example application from the official RuStore repository on GitFlic;

  2. Open the Android project from the godot_plugin_libraries folder in your IDE.

  3. Save the godot-lib.xxx.yyy.template_release.aar package to godot_plugin_libraries / libs folder, where xxx.yyy is the version of your Godot Engine edition.

  4. Use the gradle assemble command to assemble the project.

If the build is successful, files will be created in godot_example / android / plugins:

  • RuStoreGodotPush.gdap;
  • RuStoreGodotPush.aar;
  • RuStoreGodotCore.gdap;
  • RuStoreGodotCore.aar.
caution

Please note that plugin libraries must be built for your version of Godot Engine.

  1. Copy the contents of godot_example / android / plugins to your_project / android / plugins.

  2. Copy and replace the contents of godot_example / android / build_example to godot_example / android / build.

  3. In the Plugins list tick the RuStore Godot Review and RuStore Godot Core plugins in your Android build preset.

Editing app manifest

In the manifest file your_project / android / build / AndroidManifest.xml, declare a service that extends RuStoreMessagingService:

AndroidManifest.xml
<service
android:name="ru.rustore.godot.pushclient.RuStoreGodotMessagingService"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="ru.rustore.sdk.pushclient.MESSAGING_EVENT" />
</intent-filter>
</service>

If you need to change the icon or colour of the standard notification, add:

AndroidManifest.xml
<meta-data
android:name="ru.rustore.sdk.pushclient.default_notification_icon"
android:resource="@drawable/ic_baseline_android_24" />
<meta-data
android:name="ru.rustore.sdk.pushclient.default_notification_color"
android:resource="@color/your_favorite_color" />

If you need to override the notification channel, add:

AndroidManifest.xml
<meta-data
android:name="ru.rustore.sdk.pushclient.default_notification_channel_id"
android:value="@string/pushes_notification_channel_id" />

You must create the channel yourself if you add a push notification channel.

Requesting permissions for displaying notifications in Android 13+

The Android 13 version has a new permission to display push notifications. This will affect all apps that run on Android 13 or higher and use RuStore Push SDK.

By default, RuStore Push SDK version 1.4.0 and above includes the POST_NOTIFICATIONS permission defined in the manifest. However, the application also needs to request this permission at runtime via the android.permission.POST_NOTIFICATIONS constant. The app will only be able to show push notifications if the user grants a permission.

Request permission to show push notifications:

Activity/Fragment
// Declare the launcher at the top of your Activity/Fragment:
private final ActivityResultLauncher<String> requestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
// RuStore Push SDK (and your app) can post notifications.
} else {
// TODO: Inform user that your app will not show notifications.
}
});

private void askNotificationPermission() {
// This is only necessary for API level>= 33 (TIRAMISU)
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
PackageManager.PERMISSION_GRANTED) {
// RuStore Push SDK (and your app) can post notifications.
} else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
// TODO: display an educational UI explaining to the user the features that will be enabled
// by them granting the POST_NOTIFICATION permission. This UI should provide the user
// "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
// If the user selects "No thanks," allow the user to continue without notifications.
} else {
// Directly ask for the permission
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
}
}
}

Initialization

For initialisation you will need project ID from the RuStore Console. To get the project ID on the app page navigate to Push notifications > Projects and copy the value in the Project ID field.

img

Push notifications SDK initialization

Add the following code to AndroidManifest.xml:

AndroidManifest.xml
<meta-data
android:name="ru.rustore.sdk.pushclient.project_id"
android:value="i5UTx96jw6c1C9LvdlE4cdNrWHMNyRBt" />

<meta-data
android:name="ru.rustore.sdk.pushclient.params_class"
android:value="com.godot.game.GodotPushClientParams" />
  • projectIdproject ID from the RuStore Console. To get the project ID on the app page navigate to Push notifications > Projects and copy the value in the Project ID field.
  • optional) com.godot.game.GodotPushClientParams is the full class name of RuStoreGodotPushClientParams. It is required to specify additional parameters for push client initialisation.

Example of RuStoreGodotPushClientParams:

GodotPushClientParams.java
package com.godot.game;

import android.content.Context;
import com.vk.push.common.clientid.ClientId;
import com.vk.push.common.clientid.ClientIdCallback;
import com.vk.push.common.clientid.ClientIdType;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import ru.rustore.godot.pushclient.RuStoreGodotLogger;
import ru.rustore.godot.pushclient.RuStoreGodotPushClientParams;
import ru.rustore.sdk.pushclient.common.logger.Logger;

public class GodotPushClientParams extends RuStoreGodotPushClientParams {

public final ClientIdType CLIENT_ID_TYPE = ClientIdType.GAID;
public final String CLIENT_ID_VALUE = "your_gaid_or_oaid";

public GodotPushClientParams(Context context) {
super(context);
}

@NonNull
@Override
public Logger getLogger() {
return RuStoreGodotLogger.INSTANCE;
}

@Override
public boolean getTestModeEnabled() {
return false;
}

@Nullable
@Override
public ClientIdCallback getClientIdCallback() {
return () -> new ClientId(CLIENT_ID_VALUE, CLIENT_ID_TYPE);
}
}

RuStoreGodotPushClientParams expands the class ru.rustore.sdk.pushclient.provider.AbstractRuStorePushClientParams.

caution

The implementation of the AbstractRuStorePushClientParams class should have only one constructor with one Context argument.

Calling RuStorePushClient.init() manually after automatic initialisation will be ignored.

Plugin initialization

Before calling the library methods, you must create a push notification client object RuStoreGodotPushClient. To initialise the client, run the init method.

var _push_client: RuStoreGodotPushClient = null

func _ready:
_push_client = RuStoreGodotPushClient.get_instance()
_push_client.init()

Event logging

To log push notification library events, implement getLogger in your RuStoreGodotPushClientParams inheritor. The getLogger method must return an object which implements the Logger interface.

Logger interface
interface Logger {

fun verbose(message: String, throwable: Throwable? = null)
fun debug(message: String, throwable: Throwable? = null)
fun info(message: String, throwable: Throwable? = null)
fun warn(message: String, throwable: Throwable? = null)
fun error(message: String, throwable: Throwable? = null)

fun createLogger(tag: String): Logger
}
public class DefaultLogger(
private val tag: String? = null,
) : Logger {
override fun verbose(message: String, throwable: Throwable?) {
Log.v(tag, message, throwable)
}

override fun debug(message: String, throwable: Throwable?) {
Log.d(tag, message, throwable)
}

override fun info(message: String, throwable: Throwable?) {
Log.i(tag, message, throwable)
}

override fun warn(message: String, throwable: Throwable?) {
Log.w(tag, message, throwable)
}

override fun error(message: String, throwable: Throwable?) {
Log.e(tag, message, throwable)
}

override fun createLogger(tag: String): Logger {
val newTag = if (this.tag != null) {
"${this.tag}:$tag"
} else {
tag
}
return DefaultLogger(newTag)
}
}
@NonNull
@Override
public Logger getLogger() {
return DefaultLogger("your_tag");
}

The SDK uses the default implementation with AndroidLog if you don't pass Logger:

To log events via Godot scripting, use the RuStoreGodotLogger logger. After initialising the plugin, subscribe to events once and use the init_logger method.

import ru.rustore.godot.pushclient.RuStoreGodotLogger;

@NonNull
@Override
public Logger getLogger() {
return RuStoreGodotLogger.INSTANCE;
}
func _ready:
# Initialisation _push_client

_push_client.on_log_verbose.connect(_on_log_verbose)
_push_client.on_log_debug.connect(_on_log_debug)
_push_client.on_log_info.connect(_on_log_info)
_push_client.on_log_warn.connect(_on_log_warn)
_push_client.on_log_error.connect(_on_log_error)

func _on_log_verbose(message: String):
pass

func _on_log_debug(message: String):
pass

func _on_log_info(message: String):
pass

func _on_log_warn(message: String):
pass

func _on_log_error(message: String):
pass
  • message — log report.
calling init_logger
_push_client.init_logger()

User segments

A segment is a group of users chosen based on specific criteria you set. For instance, it could include users who generate the most revenue or those using older versions of Android. Read more about the segments in MyTracker documentation.

To start working with segments, specify the ClientIdType and ClientIdValue parameters when initialising the SDK:

GodotPushClientParams.java
package com.godot.game;

import android.content.Context;
import com.vk.push.common.clientid.ClientId;
import com.vk.push.common.clientid.ClientIdCallback;
import com.vk.push.common.clientid.ClientIdType;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import ru.rustore.godot.pushclient.RuStoreGodotLogger;
import ru.rustore.godot.pushclient.RuStoreGodotPushClientParams;
import ru.rustore.sdk.pushclient.common.logger.Logger;

public class GodotPushClientParams extends RuStoreGodotPushClientParams {

public final ClientIdType CLIENT_ID_TYPE = ClientIdType.GAID;
public final String CLIENT_ID_VALUE = "your_gaid_or_oaid";

public GodotPushClientParams(Context context) {
super(context);
}

@NonNull
@Override
public Logger getLogger() {
return RuStoreGodotLogger.INSTANCE;
}

@Override
public boolean getTestModeEnabled() {
return false;
}

@Nullable
@Override
public ClientIdCallback getClientIdCallback() {
return () -> new ClientId(CLIENT_ID_VALUE, CLIENT_ID_TYPE);
}
}
  • CLIENT_ID_TYPE — ID type:
    • ClientIdType.GAID — Google's advertising ID;
    • ClientIdType.OAID — Huawei's advertising ID.
  • CLIENT_ID_VALUE — ID value.

Push notifications availability check

See SDK Prerequisites for push notifications.

To check the listed prerequisites, use the check_push_availability method.

Subscribe to events once before using this method

:

  • on_check_push_availability_success;
  • on_check_push_availability_failure.
func _ready():
# Initialisation _push_client

_push_client.on_check_push_availability_success.connect(_on_check_push_availability_success)
_push_client.on_check_push_availability_failure.connect(_on_check_push_availability_failure)

func _on_check_push_availability_success(result: RuStoreFeatureAvailabilityResult):
pass

func _on_check_push_availability_failure(error: RuStoreError):
pass
Вызов метода check_push_availability
_push_client.check_push_availability()
  • The on_check_push_availability_success callback returns a RuStoreFeatureAvailabilityResult object with service availability details.
Класс RuStoreFeatureAvailabilityResult
class_name RuStoreFeatureAvailabilityResult extends Object

var isAvailable: bool = false
var cause: RuStoreError = null

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
isAvailable = obj["isAvailable"]

if obj.has("cause"):
var jcause = JSON.stringify(obj["cause"])
cause = RuStoreError.new(jcause)
  • isAvailable — Push Notifications prerequisites:
    • true — prerequisites are met;
    • false — prerequisites are not met.
  • cause — error info. The RuStoreError class structure and all possible errors are described in Error Handling
  • The callback on_check_push_availability_failure returns a RuStoreError object with all other errors, for example — "No internet connection". The structure of RuStoreError class is described in Error Handling.

Push token methods

Getting user push token

caution

The method will create and return a new push token if the user does not have one.

Once the library has been initialised, you can use the get_token, method to get the user's current push token.

Subscribe to events once before using this method

:

  • on_get_token_success;
  • on_get_token_failure.
func _ready():
# Initialisation _push_client

_push_client.on_get_token_success.connect(_on_get_token_success)
_push_client.on_get_token_failure.connect(_on_get_token_failure)

func _on_get_token_success(data: String):
pass

func _on_get_token_failure(error: RuStoreError):
pass
_push_client.get_token()
  • The callback on_get_token_success returns a string with current push token details.

  • The on_get_token_failure callback returns a RuStoreError object with error details. The structure of RuStoreError class is described in Error Handling.

Deleting user push token

After the library has been initialised, the user's current push token can be removed using the delete_token method.

Subscribe to events once before using this method

:

  • on_delete_token_success;
  • on_delete_token_failure.
func _ready():
# Initialisation _push_client

_push_client.on_delete_token_success.connect(_on_delete_token_success)
_push_client.on_delete_token_failure.connect(_on_delete_token_failure)

func _on_delete_token_success():
pass

func _on_delete_token_failure(error: RuStoreError):
pass
Вызов метода delete_token
_push_client.delete_token()

The on_delete_token_failure callback returns a RuStoreError object with error details. The structure of RuStoreError class is described in Error Handling.

Push topic methods

Push topic subscription

Once the library is initialised, you can use the subscribe_to_topic method to subscribe to a topic.

Subscribe to events once before using this method

:

  • on_subscribe_to_topic_success;
  • on_subscribe_to_topic_failure.
func _ready():
# Initialisation _push_client

_push_client.on_subscribe_to_topic_success(_on_subscribe_to_topic_success)
_push_client.on_subscribe_to_topic_failure(_on_subscribe_to_topic_failure)

func _on_subscribe_to_topic_success():
pass

func _on_subscribe_to_topic_failure(error: RuStoreError):
pass
Вызов метода subscribe_to_topic
const TOPIC_NAME = "hello"

_push_client.subscribe_to_topic(TOPIC_NAME)
  • TOPIC_NAME — topic name.

The callback on_subscribe_to_topic_success indicates that the operation succeeded.

The on_subscribe_to_topic_failure callback returns a RuStoreError object with error info. The structure of RuStoreError class is described in Error Handling.

Unsubscribe from push topic

Once the library is initialised, you can use the unsubscribe_from_topic method to unsubscribe from the topic.

Subscribe to events once before using this method

:

  • on_unsubscribe_from_topic_success;
  • on_unsubscribe_from_topic_failure.
func _ready():
# Initialisation _push_client

_push_client.on_unsubscribe_from_topic_success(_on_unsubscribe_from_topic_success)
_push_client.on_unsubscribe_from_topic_failure(_on_unsubscribe_from_topic_failure)

func _on_unsubscribe_from_topic_success():
pass

func _on_unsubscribe_from_topic_failure(error: RuStoreError):
pass
};
Calling unsubscribe_from_topic
const TOPIC_NAME = "hello"

_push_client.unsubscribe_from_topic(TOPIC_NAME)
  • TOPIC_NAME — topic name.

The callback on_unsubscribe_to_topic_success indicates that the operation was successful.

The on_unsubscribe_to_topic_failure callback returns a RuStoreError object with error details. The structure of RuStoreError class is described in Error Handling.

Retrieving data from RuStore SDK

To receive push notification data from RuStore SDK, once the client has been created and initialised, subscribe to events once:

  • on_new_token;
  • on_message_received;
  • on_deleted_messages;
  • on_error.
func _ready:
# Initialisation _push_client

_push_client.on_new_token.connect(_on_new_token)
_push_client.on_message_received.connect(_on_message_received)
_push_client.on_deleted_messages.connect(_on_deleted_messages)
_push_client.on_error.connect(_on_error)

func _on_new_token(data: String):
pass

func _on_message_received(data: Dictionary):
pass

func _on_deleted_messages():
pass

func _on_error(errors: Array):
pass
Method nameDescription

on_new_token

Called when a new push token is received. After this method is called, your app will be responsible for delivering the new push token to its server. This method returns the value of the new token.

on_message_received

Called when a new push token is received < p/> If there is data in notification object, RuStoreSDK will display the notification itself. If you don’t want RuStoreSDK to display notification itself, use data object, and leave notification object empty. Called in any case. < p/> Push notification’s payload may be obtained from data[data] field.

on_deleted_messages

Called when one or more push notifications fail to reach the device. For example, if the notification's lifetime has expired before delivery. < p/> When calling this method, it is recommended that you synchronise with your server to avoid missing data.

on_error

Called when an error occurs during initialisation. It returns an array of objects with errors. < p/> Possible errors:

  • UnauthorizedException — user not authorized on RuStore.
  • HostAppNotInstalledException — user’s device doesn’t have RuStore app installed.
  • HostAppBackgroundWorkPermissionNotGranted — RuStore app is not allowed to run in the background.
All possible errors are described in Error handling.

Notification structure

func _on_message_received(data: Dictionary):
print("messageId: " + data["messageId"])
print("priority: " + data["priority"])
print("ttl: " + data["ttl"])
print("collapseKey: " + data["collapseKey"])
print("data: " + data["data"])
print("rawData: " + data["rawData"])
  • messageId — unique message ID. It corresponds to an ID of each message.

  • priority — returns the priority value (currently disregarded).

    The following options are now available:

    • 0UNKNOWN.
    • 1HIGH.
    • 2NORMAL.

    < p/>

  • ttl — push notification lifetime of Int type in seconds.

  • from — field which shows the notification's origin: < p/>

    • The field displays the topic name for notifications sent to it.
    • Otherwise it is part of your service token.

    < p/>

  • collapseKey - notification group ID (currently disregarded).

  • data — dictionary to which additional notification data can be passed.

    .

  • rawData — dictionary of data as an array of bytes.

  • notification — notification object.

func _on_message_received(data: Dictionary):
print("title: " + data["notification_title"])
print("body: " + data["notification_body"])
print("channelId: " + data["notification_channelId"])
print("color: " + data["notification_color"])
print("icon: " + data["notification_icon"])
print("clickAction: " + data["notification_clickAction"])
print("imageUrl: " + data["notification_imageUrl"])
  • title — notification header.

  • body — notification body
  • channelId — option to create the channel to which notification will be sent. For Android 8.0 or later.

  • imageUrl — direct link to an image to be inserted into the notification. The size of the image must not exceed 1 Mbyte .

    .

  • color — notification colour in HEX format, string. For example, #0077FF.

  • icon — notification icon from res/drawable in a string format that matches the resource name. < p/> For example, res/drawable has an icon small_icon.xml, which is accessible in code via R.drawable.small_icon. For the icon to be displayed in the notification, the server must specify a icon value of small_icon. < p/>

  • clickActionintent action, with which activity is opened when a notification is pressed on..

Creating notification channel

The channel to which the message is sent will be given the following priority:

  • If the push notification has a channelId field, RuStore SDK will send the notification to the specified channel. Your app must create this channel in advance.

  • If there is no channelId field in the push notification, but your app has specified a parameter with a channel in AndroidManifest.xml, the specified channel will be used. Your app must create this channel in advance.

  • If there is no channelId field in the push notification and the default channel is not set in AndroidManifest.xml, RuStore SDK will create a channel and send the notification to it. From now on, all notifications without an explicit channel will be sent to that channel..

Tap notification to open activity

By default, if you click on a notification, RuStore SDK will open an activity with action android.intent.action.MAIN. If there is a clickAction field, RuStore SDK will open an activity that falls under the Intent filter with the specified action.

Add the string <category android:name="android.intent.category.DEFAULT" /> in the application manifest in the corresponding <intent-filter> element of the activity. This is to open the activity by default when you click on the notification. The activity will not open without this line in RuStore SDK.

For the SDK to open game activity without reloading the game, you need to clear intent when you navigate to the app after a push notification. To do this

  1. Go to your_project / android / build / src / com /godot / game.

  2. Create the GodotPushApp class, a descendant of FullScreenGodotApp:

    package com.godot.game;

    import org.godotengine.godot.FullScreenGodotApp;
    import android.os.Bundle;

    public class GodotPushApp extends FullScreenGodotApp {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.GodotAppMainTheme);
    super.onCreate(savedInstanceState);
    }
    }
  3. Change the class of GodotApp:

    package com.godot.game;

    import android.content.Intent;
    import android.os.Bundle;
    import androidx.appcompat.app.AppCompatActivity;

    public class GodotApp extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.GodotAppMainTheme);
    super.onCreate(savedInstanceState);

    /**
    * Processing intenss here
    */

    Intent newIntent = new Intent(this, GodotPushApp.class);
    startActivity(newIntent);
    finish();
    }
    }
  4. Add information about the GodotPushApp activity to the your_project / android / build / AndroidManifest.xml manifest.

AndroidManifest.xml
 <activity
android:name="com.godot.game.GodotPushApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleInstance"
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="sensor"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
</activity>
  1. Change android:launchMode="singleInstance" to android:launchMode="singleTask" in the android:name=".GodotApp" activity.

Errors processing

Error structure
class_name RuStoreError extends Object

var description: String

func _init(json: String = ""):
if json == "":
description = ""
else:
var obj = JSON.parse_string(json)
description = obj["detailMessage"]
  • description — error description.

Error Classes:

  • RuStoreNotInstalledException — RuStore is not installed on the user's device.

  • RuStoreOutdatedException — RuStore app on the user's device does not support push notifications.

  • RuStoreUserUnauthorizedException — user is not authorized in RuStore.

  • RuStoreFeatureUnavailableException — RuStore is not allowed to work in background.

  • RuStoreException — basic RuStore error from which other errors are inherited.

See also