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
-
Copy the plugin project and example application from the official RuStore repository on GitFlic;
-
Open the Android project from the
godot_plugin_libraries
folder in your IDE. -
Save the
godot-lib.xxx.yyy.template_release.aar
package togodot_plugin_libraries / libs
folder, where xxx.yyy is the version of your Godot Engine edition. -
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
.
Please note that plugin libraries must be built for your version of Godot Engine.
-
Copy the contents of
godot_example / android / plugins
toyour_project / android / plugins
. -
Copy and replace the contents of
godot_example / android / build_example
togodot_example / android / build
. -
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
:
<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:
<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:
<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:
// 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.
Push notifications SDK initialization
Add the following code to 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" />
projectId
— 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.- optional)
com.godot.game.GodotPushClientParams
is the full class name ofRuStoreGodotPushClientParams
. It is required to specify additional parameters for push client initialisation.
Example of RuStoreGodotPushClientParams
:
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
.
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.
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.
_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:
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
_push_client.check_push_availability()
- The
on_check_push_availability_success
callback returns aRuStoreFeatureAvailabilityResult
object with service availability details.
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. TheRuStoreError
class structure and all possible errors are described in Error Handling
- The callback
on_check_push_availability_failure
returns aRuStoreError
object with all other errors, for example — "No internet connection". The structure ofRuStoreError
class is described in Error Handling.
Push token methods
Getting user push token
The method will create and return a new push token if the user does not have one.
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 aRuStoreError
object with error details. The structure ofRuStoreError
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
_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
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 theunsubscribe_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
};
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 name | Description |
---|---|
| 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. |
| Called when a new push token is received
< p/>
If there is data in |
| 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. |
| Called when an error occurs during initialisation. It returns an array of objects with errors. < p/> Possible errors:
|
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:
0
—UNKNOWN
.1
—HIGH
.2
—NORMAL
.
< p/>
-
ttl
— push notification lifetime ofInt
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 ofdata
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 fromres/drawable
in a string format that matches the resource name. < p/> For example,res/drawable
has an iconsmall_icon.xml
, which is accessible in code viaR.drawable.small_icon
. For the icon to be displayed in the notification, the server must specify aicon
value ofsmall_icon
. < p/> -
clickAction
—intent 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 inAndroidManifest.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 inAndroidManifest.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
-
Go to
your_project / android / build / src / com /godot / game
. -
Create the
GodotPushApp
class, a descendant ofFullScreenGodotApp
: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);
}
} -
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();
}
} -
Add information about the
GodotPushApp
activity to theyour_project / android / build / AndroidManifest.xml
manifest.
<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>
- Change
android:launchMode="singleInstance"
toandroid:launchMode="singleTask"
in theandroid:name=".GodotApp"
activity.
Errors processing
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.