SDK push-уведомлений для Godot Engine (версия 1.4.0)
Условия корректной работы SDK
Ниже перечислены условия работы push-уведомлений.
- Подпись тестируемой сборки (например,
debug
) приложения должна совпадать с подписью сборки приложения, которая была загружена в консоль и прошла модерацию ранее (например,release
).
- Используется актуальная версия SDK.
- Приложение загружено в Консоль RuStore.
- Приложение прошло модерацию (публиковать приложение необязательно).
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность push-уведомлений.
- Приложению RuStore разрешен доступ к работе в фоновом режиме.
- Без этого разрешения push-уведомления будут приходить, но со значительной задержкой.
- Отпечаток подписи приложения, установленного на девайсе, совпадает с отпечатком подписи приложения, которое загружено в Консоль RuStore.
- Версия Godot 4 или выше.
Пример реализации
Ознакомьтесь с приложением-примером, чтобы узнать, как правильно интегрировать SDK push-уведомлений.
Подключение в проект
-
Скопируйте проекты плагина и приложения-примера из официального репозитория RuStore на GitFlic.
-
Откройте в вашей IDE проект Android из папки
godot_plugin_libraries
. -
Поместите в папку
godot_plugin_libraries/libs
пакетgodot-lib.xxx.yyy.template_release.aar
, гдеxxx.yyy
версия вашей редакции Godot Engine. -
Выполните сборку проекта командой
gradle assemble
.
При успешном выполнении сборки в папке godot_example/android/plugins
будут созданы файлы:
RuStoreGodotPush.gdap
;RuStoreGodotPush.aar
;RuStoreGodotCore.gdap
;RuStoreGodotCore.aar
.
Обратите особое внимание, что библиотеки плагинов должны быть собраны под вашу версию Godot Engine.
- Скопируйте содержимое папки
godot_example/android/plugins
в папкуyour_project/android/plugins
. - Скопируйте с заменой содержимое папки
godot_example/android/build_example
в папкуgodot_example/android/build
. - В пресете сборки Android в списке Плагины отметьте Ru Store Godot Push и Ru Store Godot Core.
Редактирование манифеста приложения
В файле манифеста your_project/android/build/AndroidManifest.xml
объявите службу, расширяющую 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>
Если нужно изменить иконку или цвет стандартной нотификации, добавьте следующий код.
<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" />
Если нужно переопределить канал уведомлений, добавьте следующий код.
<meta-data
android:name="ru.rustore.sdk.pushclient.default_notification_channel_id"
android:value="@string/pushes_notification_channel_id" />
При добавлении канала push-уведомлений вы должны создать канал самостоятельно.
Запрос разрешения на показ уведомлений в Android 13+
В версии Android 13 появилось новое разрешение для отображения push-уведомлений. Это затронет все приложения, которые работают на Android 13 или выше и используют RuStore Push SDK.
По умолчанию RuStore Push SDK версии 1.4.0 и выше включает разрешение POST_NOTIFICATIONS
, определённое в манифесте.
Однако приложению также нужно запросить это разрешение во время выполнения через константу android.permission.POST_NOTIFICATIONS
.
Приложение сможет показывать push-уведомления, только когда пользователь предоставит на это разрешение.
Запрос разрешения на показ push-уведомлений.
// 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);
}
}
}
Инициализация
Для инициализации понадобится идентификатор проекта из RuStore Консоль. Чтобы получить его, на странице приложения перейдите в раздел Push-уведомления > Проекты и скопируйте значение в поле ID проекта.
Инициализация SDK push-уведомлений
Добавьте в 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
— идентификатор проекта из RuStore Консоль. Чтобы получить его, на странице приложения перейдите в раздел Push-уведомления > Проекты и скопируйте значение в поле ID проекта.- (опционально)
com.godot.game.GodotPushClientParams
— полное имя класса своей реализацииRuStoreGodotPushClientParams
. Параметр нужен для указания дополнительных параметров инициализации push-клиента.
Пример реализации 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
расширяет класс ru.rustore.sdk.pushclient.provider.AbstractRuStorePushClientParams
.
В реализации класса AbstractRuStorePushClientParams
должен быть только один конструктор с одним аргументом Context
.
Ручной вызов RuStorePushClient.init()
после автоматической инициализации будет проигнорирован.
Инициализация плагина
Перед вызовом методов библиотеки необходимо создать объект клиента push-уведомлений RuStoreGodotPushClient
. Для инициализации клиента выполните метод init
.
var _push_client: RuStoreGodotPushClient = null
func _ready:
_push_client = RuStoreGodotPushClient.get_instance()
_push_client.init()
Логирование событий
Если вам необходимо логировать события библиотеки push-уведомлений, реализуйте в вашем наследнике RuStoreGodotPushClientParams
метод getLogger
. Метод getLogger
должен возвращать объект реализующий интерфейс Logger
.
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");
}
Если не передать Logger
, SDK использует реализацию по умолчанию с AndroidLog
.
Чтобы логировать события с использованием скриптинга Godot, используйте релизацию логгера RuStoreGodotLogger
. После инициализации плагина единожды выполните подписку на события и воспользуйтесь методом init_logger
.
import ru.rustore.godot.pushclient.RuStoreGodotLogger;
@NonNull
@Override
public Logger getLogger() {
return RuStoreGodotLogger.INSTANCE;
}
func _ready:
# Инициализация _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
— сообщение лога.
_push_client.init_logger()
Работа с сегментами пользователей
Сегмент — это группа пользователей, которых вы выбираете по определенным параметрам. Например, пользователи, которые приносят наибольший доход, или пользователи со старой версией Android. Подробности о сегментах — в документации MyTracker.
Чтобы н ачать работу с сегментами, укажите ClientIdType
и ClientIdValue
при инициализации 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
— тип идентификатора:ClientIdType.GAID
— рекламный идентификатор Google;ClientIdType.OAID
— рекламный идентификатор Huawei.
CLIENT_ID_VALUE
— значение иден тификатора.
Проверка возможности получать push-уведомления
Условия работы push-уведомлений приведены в разделе Условия корректной работы SDK.
Для проверки того, что приложение RuStore установлено на устройстве пользователя, используйте методcheck_push_availability
.
Перед использованием метода единожды выполните подписку на события:
on_check_push_availability_success
;on_check_push_availability_failure
.
func _ready():
# Инициализация _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()
- Обратный вызов (callback)
on_check_push_availability_success
возвращает объект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-уведомлений:true
— условия выполнены;false
— условия не выполнены.
cause
— информация об ошибке. Структура классаRuStoreError
и все возможные ошибки описаны в разделе Обработка ошибок
- Обратный вызов (callback)
on_check_push_availability_failure
возвращает объектRuStoreError
со всеми прочими ошибками, например, — «Нет соединения с интернетом». Структура классаRuStoreError
описана в разделе Обработка ошибок.
Методы для работы с push-токеном
Получение push-токена пользователя
Если у пользователя нет push-токена, метод создаст и вернёт новый push-токен.
get_token
, чтобы получить текущий push-токен пользователя.
Перед использованием метода едино жды выполните подписку на события:
on_get_token_success
;on_get_token_failure
.
func _ready():
# Инициализация _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()
-
Обратный вызов (callback)
on_get_token_success
возвращает строку с информацией о текущем push-токене. -
Обратный вызов (callback)
on_get_token_failure
возвращает объектRuStoreError
с информацией об ошибке. Структура классаRuStoreError
описана в разделе Обработка ошибок.
Удаление push-токена пользователя
После инициализации библиотеки вы можете использовать методdelete_token
, чтобы удалить текущий push-токен пользователя.
Перед использованием метода единожды выполните подписку на события:
on_delete_token_success
;on_delete_token_failure
.
func _ready():
# Инициализация _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()
Обратный вызов (callback) on_delete_token_failure
возвращает объект RuStoreError
с информацией об ошибке. Структура класса RuStoreError
описана в разделе Обработка ошибок.
Методы для работы с push-топиком
Подписка на push-уведомления по топику
После инициализации библиотеки вы можете использовать методsubscribe_to_topic
для подписки на топик.
Перед использованием метода единожды выполните подписку на события:
on_subscribe_to_topic_success
;on_subscribe_to_topic_failure
.
func _ready():
# Инициализация _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
— имя топика.
Обратный вызов (callback) on_subscribe_to_topic_success
сигнализирует об успешном выполнении операции.
Обратный вызов (callback) on_subscribe_to_topic_failure
возвращает объект RuStoreError
с информацией об ошибке. Структура класса RuStoreError
описана в разделе Обработка ошибок.
Отписка от push-уведомлений по топику
После инициализации библиотеки вы может е использовать методunsubscribe_from_topic
для отписки от топика.
Перед использованием метода единожды выполните подписку на события:
on_unsubscribe_from_topic_success
;on_unsubscribe_from_topic_failure
.
func _ready():
# Инициализация _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
— имя топика.
Обратный вызов (callback) on_unsubscribe_to_topic_success
сигнализирует об успешном выполнении операции.
Обратный вызов (callback) on_unsubscribe_to_topic_failure
возвращает объект RuStoreError
с информацией об ошибке. Структура класса RuStoreError
описана в разделе Обработка ошибок.
Получение данных от RuStore SDK
Чтобы получать данные push-уведомлений от RuStore SDK, после создания клиента и инициализации единожды выполните подписку на события:
on_new_token
;on_message_received
;on_deleted_messages
;on_error
.
func _ready:
# Инициализация _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
Название метода | Описание |
---|---|
| Метод вызывается при получении нового push-токена. После вызова этого метода ваше приложение становится ответственно за передачу нового push-токена на свой сервер. Метод возвращает значение нового токена. |
| Метод вызывается при получении нового push-уведомления. Если в объекте Получить |
| Метод вызывается, если один или несколько push-уведомлений не доставлены на устройство. Например, если время жизни уведомления истекло до момента доставки. При вызове этого метода рекомендуется синхронизироваться со своим сервером, чтобы не пропустить данные. |
| Метод вызывается, если в момент инициализации возникает ошибка. Он возвращает массив объектов с ошибками. Возможные ошибки:
|
Структура уведомления
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
— уникальный ID сообщения. Является идентификатором каждого сообщения.-
priority
— возвращает значение приоритетности (на данный момент не учитывается). Сейчас заложены следующие варианты:0
—UNKNOWN
;1
—HIGH
;2
—NORMAL
.
ttl
— время жизни push-уведомления типаInt
в секундах.from
— поле, по которому можно понять, откуда пришло уведомление:- для уведомлений, отправленных в топик, в поле отображается имя топика;
- в других случаях — часть вашего сервисного токена.
collapseKey
— идентификатор группы уведомлений (на данный момент не учитывается).data
— словарь, в который можно передать дополнительные данные для уведомления.rawData
— словарьdata
в виде массива байтов.notification
— объект уведомления.
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
— заголовок уведомления.body
— тело уведомления.channelId
— возможность задать канал, в который отправится уведомление. Актуально для Android 8.0 и выше.imageUrl
— прямая ссылка на изображение для вставки в уведомление. Изображение должно быть не более 1 Мбайт.color
— цвет уведомления в HEX-формате, строкой. Например,#0077FF
.icon
— значок уведомления изres/drawable
в формате строки, которая совпадает с названием ресурса.
Например, вres/drawable
есть значокsmall_icon.xml
, который доступен в коде черезR.drawable.small_icon
.
Чтобы значок отображался в уведомлении, сервер должен указать в параметреicon
значениеsmall_icon
.clickAction
—intent action
, с помощью которого будет открыта активити при клике на уведомление.
Создание канала для отправки уведомления
Для канала, в который отправляется уведомление, действует следующий приоритет.
-
Если в push-уведомлении есть поле
channelId
, RuStore SDK отправит уведомление в указанный канал. Ваше приложение должно создать этот канал заранее. -
Если в push-уведомлении нет поля
channelId
, но ваше приложение указало параметр с каналом вAndroidManifest.xml
, используется указанный канал. Ваше приложение должно создать этот канал заранее. -
Если в push-уведомлении нет поля
channelId
, и канал по умолчанию не задан вAndroidManifest.xml
, RuStore SDK создаст канал и отправит уведомление в него. В дальнейшем все уведомления без явного указания канала будут отправляться в этот канал.
Открытие activity при нажатии на уведомление
По умолчанию, если нажать на уведомление, RuStore SDK откроет activity с action
android.intent.action.MAIN
.
Если есть поле clickAction
, RuStore SDK откроет activity, которая попадает под Intent filter
с указанным action
.
Добавьте строку <category android:name="android.intent.category.DEFAULT" />
в мани фесте приложения в соответствующем элементе <intent-filter>
у activity.
Это нужно, чтобы при нажатии на уведомление по умолчанию открывалась activity.
Без этой строки в RuStore SDK activity не откроется.
Чтобы SDK смог открыть game activity без перезагрузки игры, нужно очистить intent
при переходе в приложение после нажатия на push-уведомление.
Для этого:
-
Перейдите в папку
your_project/android/build/src/com /godot/game
. -
Создайте класс
GodotPushApp
, наследника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);
}
}
- Измените класс
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();
}
}
- Добавьте информацию об activity
GodotPushApp
в манифестyour_project/android/build/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>
- Измените
android:launchMode="singleInstance"
наandroid:launchMode="singleTask"
в activityandroid:name=".GodotApp"
.
Обработка ошибок
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
— описание ошибки.
Ниже представлены классы ошибок.
RuStoreNotInstalledException
— на устройстве пользователя не установлен RuStore.RuStoreOutdatedException
— версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK.RuStoreUserUnauthorizedException
— пользователь не авторизован в RuStore.RuStoreFeatureUnavailableException
— RuStore не имеет разрешения на работу в фоне.RuStoreException
— базовая ошибка RuStore, от которой наследуются остальные ошибки.