Skip to main content

SDK push-уведомлений для Unity (версия 6.3.0)

Условия корректной работы SDK

Ниже перечислены условия работы push-уведомлений.

Важно
  • Подпись тестируемой сборки (например, debug) приложения должна совпадать с подписью сборки приложения, которая была загружена в консоль и прошла модерацию ранее (например, release).
  • Используется актуальная версия SDK.
  • Приложение загружено в Консоль RuStore.
  • Приложение прошло модерацию (публиковать приложение необязательно).
  • На устройстве пользователя установлена актуальная версия RuStore.
  • Приложение RuStore поддерживает функциональность push-уведомлений.
  • Приложению RuStore разрешен доступ к работе в фоновом режиме. Без этого разрешения push-уведомления будут приходить, но со значительной задержкой.
  • Отпечаток подписи приложения, установленного на девайсе, совпадает с отпечатком подписи приложения, которое загружено в Консоль RuStore.

Пример реализации

Ознакомьтесь с приложением-примером, чтобы узнать, как правильно интегрировать SDK push-уведомлений.

Подключение в проект

Для подключения скачайте файлы:

и импортируйте в проект через Package Manager (Window > Package Manager > + > Add package from tarball...).

Зависимости подключаются автоматически с помощью External Dependency Manager:

  1. Откройте окно менеджера пакетов (Window > Package Manager > + > Add package from git URL...).
  2. Используйте ссылку https://github.com/googlesamples/unity-jar-resolver.git?path=/upm для подключения пакета.
  3. Для устранения ошибки Google.IOSResolver.dll will not be loaded установите модуль сборки iOS для вашей версии Unity (UnityHub > Installs > Ваша версия Unity > Add modules > iOS Build Support).
Ошибка Google.IOSResolver.dll
Assembly 'Packages/com.google.external-dependency-manager/ExternalDependencyManager/Editor/1.2.182/Google.IOSResolver.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.
tip

Если вы используете операционную систему macOS, измените настройки утилиты архивации. В настройках Archive Utility снимите флажок Keep expanding if possible. В противном случае архив проекта будет скачан некорректно.

Для корректной обработки зависимостей SDK выполните следующие настройки.

  1. Откройте настройки проекта: Edit → Project Settings → Player → Android Settings.

  2. В pазделе Publishing Settings включите следующие настройки.

    • Custom Main Manifest.
    • Custom Main Gradle Template.
    • Custom Gradle Properties Template.
  3. В разделе Other Settings настройте:

    • package name.
    • Minimum API Level = 24.
    • Target API Level = 34.
  4. Откройте настройки External Dependency Manager: Assets → External Dependency Manager → Android Resolver → Settings, включите следующие настройки.

    • Use Jetifier.
    • Patch mainTemplate.gradle.
    • Patch gradleTemplate.properties.
  5. Обновите зависимости проекта: Assets → External Dependency Manager → Android Resolver → Force Resolve.

Редактирование манифеста приложения

Объявите службу RuStoreUnityMessagingService.

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

Если нужно изменить иконку или цвет стандартной нотификации, добавьте следующий код.

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" />

Если нужно переопределить канал уведомлений, добавьте следующий код.

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

При добавлении канала push-уведомлений вы должны создать канал самостоятельно.

Чтобы иметь возможность перехода в приложение по тапу push-сообщение, вы должны сделать RuStoreUnityActivity основным активити. Для этого добавьте следующую запись в манифест вашего проекта.

<activity android:name="ru.rustore.unitysdk.RuStoreUnityActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Одновременно, вы должны удалить следующий <intent-filter> из активити com.unity3d.player.UnityPlayerActivity.

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

Совместимость с другими плагинами

Класс RuStoreUnityActivity выполнит обработку Intents и запустит UnityPlayerActivity. Это необходимо, чтобы правильно обработать переход в приложение по тапу на push-уведомление.

Если вам необходимо изменить это поведение, модифицируйте файл RuStoreUnityActivity.java: RuStoreSDK > PushClient > Android заменив UnityPlayerActivity своим классом.

Запрос разрешения на показ уведомлений в Android 13+

В версии Android 13 появилось новое разрешение для отображения push-уведомлений. Это затронет все приложения, которые работают на Android 13 или выше и используют RuStore Push SDK.

По умолчанию RuStore Push SDK версии 1.4.0 и выше включает разрешение POST_NOTIFICATIONS, определённое в манифесте. Однако приложению также нужно запросить это разрешение во время выполнения через константу android.permission.POST_NOTIFICATIONS. Приложение сможет показывать push-уведомления, только когда пользователь предоставит на это разрешение.

Запрос разрешения на показ push-уведомлений.

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);
}
}
}

Инициализация

Для инициализации понадобится идентификатор проекта из RuStore Консоль. Чтобы получить его, на странице приложения перейдите в раздел Push-уведомления > Проекты и скопируйте значение в поле ID проекта.

img

Автоматическая инициализация

Добавьте в 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="ru.rustore.unitysdk.pushclient.RuStorePushClientParamsExample" />
  • projectIdидентификатор проекта из RuStore Консоль. Чтобы получить его, на странице приложения перейдите в раздел Push-уведомления > Проекты и скопируйте значение в поле ID проекта.
  • params_class (опционально) — полное имя класса своей реализации AbstractRuStorePushClientParams. Параметр нужен для указания дополнительных параметров инициализации push-клиента.

Пример реализации RuStorePushClientParamsExample.

RuStorePushClientParamsExample.java
package ru.rustore.unitysdk.pushclient;

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 ru.rustore.sdk.pushclient.common.logger.Logger;
import ru.rustore.sdk.pushclient.provider.AbstractRuStorePushClientParams;

public class RuStorePushClientParamsExample extends AbstractRuStorePushClientParams {

private boolean isTestModeEnabled;

public RuStorePushClientParamsExample(Context context) {
super(context);

int testMode = context.getResources().getIdentifier("rustore_PushClientSettings_testMode", "string", context.getPackageName());
isTestModeEnabled = context.getString(testMode).equalsIgnoreCase("true");
}

@Override
public Logger getLogger() {
return new UnityLogger("RuStoreUnityPushClient");
}

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

@Override
public ClientIdCallback getClientIdCallback() {
return () -> new ClientId("your_gaid_or_oaid", ClientIdType.GAID);
}
}

Ручная инициализация в Application

Для ручной инициализации SDK создайте класс RuStorePushApplication расширяющий класс Application в вашем проекте. В методе onCreate вызовите RuStoreUnityPushClient.INSTANCE.init.

RuStorePushApplication.java
package ru.rustore.unitysdk;

import android.app.Application;
import ru.rustore.unitysdk.pushclient.RuStoreUnityPushClient;
import ru.rustore.unitysdk.pushclient.RuStoreUnityLoggerMode;

public class RuStorePushApplication extends Application {
public final String PROJECT_ID = "-Yv4b5cM2yfXm0bZyY6Rk7AHX8SrHmLI";

@Override
public void onCreate() {
super.onCreate();

RuStoreUnityPushClient.INSTANCE.init(
this,
PROJECT_ID,
RuStoreUnityLoggerMode.UNITYLOGGER,
"RuStoreUnityPushClient",
false,
null,
null
);
}
}
  • application: Application — экземпляр класса Application.
  • projectId: String — идентификатор вашего проекта из RuStore Консоль.
  • loggerMode: RuStoreUnityLoggerMode
    • DEFAULTLOGGER — логгер, по умолчанию используется вывод в logcat.
    • UNITYLOGGER — логгер unity, события лога будут автоматически проброшены в реализацию ILogListener.
  • loggerTag: String — тег с которым будут выводиться записи лога.
  • testModeEnabled: Boolean — тестовый режим работы SDK.
  • clientIdType: RuStoreUnityClientIdType? — тип идентификатора:
    • ClientIdType.GAID — рекламный идентификатор Google;
    • ClientIdType.OAID — рекламный идентификатор Huawei.
  • clientIdValue: String? — значение идентификатора (your_gaid_or_oaid).

В файле AndroidManifest.xml добавьте атрибут android:name к тегу application.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="rustore.unitysdk.sample" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application android:name="ru.rustore.unitysdk.RuStorePushApplication">
<activity android:name="ru.rustore.unitysdk.RuStoreUnityActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector" android:exported="true">
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<service android:name="ru.rustore.unitysdk.pushclient.RuStoreUnityMessagingService" android:exported="true" tools:ignore="ExportedService">
<intent-filter>
<action android:name="ru.rustore.sdk.pushclient.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>

Инициализация плагина

Перед вызовом методов плагина необходимо создать объект клиента push-уведомлений RuStorePushClient. Для инициализации клиента выполните метод init.

Создание клиента
public class Example : MonoBehaviour, IMessagingServiceListener, ILogListener {
private void Awake() {
var pushConfig = new RuStorePushClientConfig() {
allowNativeErrorHandling = true,
messagingServiceListener = this,
logListener = this
};

RuStorePushClient.Instance.Init(pushConfig);
}

/* Реализация интерфейсов IMessagingServiceListener, ILogListener */
}

Логирование событий

Если вам необходимо логировать события библиотеки push-уведомлений, реализуйте в вашем наследнике AbstractRuStorePushClientParams метод getLogger. Метод getLogger должен возвращать объект реализующий интерфейс Logger.

Интерфейс 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
}
Пример реализации логгера
package ru.rustore.unitysdk.pushclient

import android.util.Log
import ru.rustore.sdk.pushclient.common.logger.Logger

class UnityLogger (
private val tag: String? = null,
) : Logger {

override fun verbose(message: String, throwable: Throwable?) {
Log.v(tag, message, throwable)
RuStoreUnityPushClient.Log("[V] $tag $message");
logException(throwable)
}

override fun debug(message: String, throwable: Throwable?) {
Log.d(tag, message, throwable)
RuStoreUnityPushClient.Log("[D] $tag $message");
logException(throwable)
}

override fun info(message: String, throwable: Throwable?) {
Log.i(tag, message, throwable)
RuStoreUnityPushClient.Log("[I] $tag $message");
logException(throwable)
}

override fun warn(message: String, throwable: Throwable?) {
Log.w(tag, message, throwable)
RuStoreUnityPushClient.LogWarning("[W] $tag $message");
logException(throwable)
}

override fun error(message: String, throwable: Throwable?) {
Log.e(tag, message, throwable)
RuStoreUnityPushClient.LogError("[E] $tag $message");
logException(throwable)
}

private fun logException(throwable: Throwable?) {
if (throwable != null) {
RuStoreUnityPushClient.LogException(throwable)
}
}

override fun createLogger(tag: String): Logger {
val newTag = if (this.tag != null) {
"${this.tag}:$tag"
} else {
tag
}

return UnityLogger(newTag)
}
}
Метод getLogger
@NonNull
@Override
public Logger getLogger() {
return UnityLogger("your_tag");
}

Если не передать Logger, SDK использует реализацию по умолчанию с AndroidLog.

Чтобы логировать события с использованием скриптинга Unity, используйте релизацию интерфеса ILogListener. Объект реализующий интерфейс должен быть передан в методе инициализации плагина.

Интерфейс ILogListener
namespace RuStore.PushClient {

public interface ILogListener {

public void Log(string logString);
public void LogWarning(string logString);
public void LogError(string logString);
}
}

Работа с сегментами пользователей

Сегмент — это группа пользователей, которых вы выбираете по определенным параметрам. Например, пользователи, которые приносят наибольший доход, или пользователи со старой версией Android. Подробности о сегментах — в документации MyTracker.

Чтобы начать работу с сегментами, укажите ClientIdType и ClientIdValue при инициализации SDK.

RuStorePushClientParamsExample.java
public class RuStorePushClientParamsExample extends AbstractRuStorePushClientParams {

/* Реализация AbstractRuStorePushClientParams */

@Override
public ClientIdCallback getClientIdCallback() {
return () -> new ClientId("your_gaid_or_oaid", ClientIdType.GAID);
}
}
  • CLIENT_ID_VALUE — значение идентификатора (your_gaid_or_oaid).
  • CLIENT_ID_TYPE — тип идентификатора:
    • ClientIdType.GAID — рекламный идентификатор Google;
    • ClientIdType.OAID — рекламный идентификатор Huawei.

Проверка возможности получать push-уведомления

Для проверки того, что приложение RuStore установлено на устройстве пользователя, используйте метод RuStorePushClient.checkPushAvailability.
RuStorePushClient.Instance.CheckPushAvailability(
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
if (!response.isAvailable) {
// Process push unavailable
}
}
);

Методы для работы с push-токеном

Получение push-токена пользователя

caution

Если у пользователя нет push-токена, метод создаст и вернёт новый push-токен.

После инициализации библиотеки вы можете использовать метод RuStorePushClient.getToken(), чтобы получить текущий push-токен пользователя.
Вызов метода GetToken
RuStorePushClient.Instance.GetToken(
onFailure: (error) => {
// Process error
},
onSuccess: (token) => {
// Process success
}
);

Удаление push-токена пользователя

После инициализации библиотеки вы можете использовать метод RuStorePushClient.deleteToken(), чтобы удалить текущий push-токен пользователя.
Вызов метода DeleteToken
RuStorePushClient.Instance.DeleteToken(
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);

Методы для работы с push-топиком

Подписка на push-уведомления по топику

После инициализации библиотеки вы можете использовать метод SubscribeToTopic(your_topic_name) для подписки на топик.
Вызов метода SubscribeToTopic
RuStorePushClient.Instance.SubscribeToTopic(
topicName: "your_topic_name",
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);

Отписка от push-уведомлений по топику

После инициализации библиотеки вы можете использовать метод UnsubscribeFromTopic(your_topic_name) для отписки от топика.
Вызов метода UnsubscribeFromTopic
RuStorePushClient.Instance.UnsubscribeFromTopic(
topicName: "your_topic_name",
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);

Получение данных от RuStore SDK

Для получения и обработки данных push-уведомлений на стороне Unity реализуйте интерфейс IMessagingServiceListener. Объект реализующий интерфейс должен быть передан в методе инициализации плагина.

IMessagingServiceListener.cs
using System.Collections.Generic;

namespace RuStore.PushClient {

public interface IMessagingServiceListener {

public void OnNewToken(string token);
public void OnMessageReceived(RemoteMessage message);
public void OnDeletedMessages();
public void OnError(List<RuStoreError> errors);
}
}
Название методаОписание

onNewToken

Метод вызывается при получении нового push-токена. После вызова этого метода ваше приложение становится ответственно за передачу нового push-токена на свой сервер. Метод возвращает значение нового токена.

onMessageReceived

Метод вызывается при получении нового push-уведомления.

Если в объекте notification есть данные, RuStore SDK самостоятельно отображает уведомление. Если вы не хотите этого, используйте объект data, а notification оставьте пустым. Метод вызывается в любом случае.

Получить payload push-уведомления Dictionary<string, string> можно из поля message.data.

DeletedMessagesResponse

Метод вызывается, если один или несколько push-уведомлений не доставлены на устройство. Например, если время жизни уведомления истекло до момента доставки.

При вызове этого метода рекомендуется синхронизироваться со своим сервером, чтобы не пропустить данные.

ErrorResponse

Метод вызывается, если в момент инициализации возникает ошибка. Он возвращает массив объектов с ошибками.

Возможные ошибки:

  • UnauthorizedException — пользователь не авторизован в RuStore. Ошибка может не возникать, даже если пользователь не авторизован в RuStore. Это поведение управляется динамически в Push SDK. Если ваши пользователи не получают такую ошибку, то все равно имеет смысл ее обрабатывать;
  • HostAppNotInstalledException — RuStore отсутствует на устройстве пользователя;
  • HostAppBackgroundWorkPermissionNotGranted — у RuStore нет разрешения на работу в фоне. Ошибка не критична. Пуши продолжат приходить, но хуже, чем если бы разрешение на работу в фоне было выдано.
Все возможные ошибки описаны в разделе Обработка ошибок.

Структура уведомления

Структура полного уведомления
public class RemoteMessage {
public string collapseKey;
public Dictionary< string, string > data;
public string messageId;
public Notification notification;
public int priority;
public sbyte [] rawData;
public int ttl;
public string from;
}
  • collapseKey — идентификатор группы уведомлений (на данный момент не учитывается).
  • data — словарь, в который можно передать дополнительные данные для уведомления.
  • messageId — уникальный ID сообщения. Является идентификатором каждого сообщения.
  • notification — объект уведомления.
  • priority — возвращает значение приоритетности (на данный момент не учитывается). Сейчас заложены следующие варианты:
    • 0UNKNOWN;
    • 1HIGH;
    • 2NORMAL.
  • rawData — словарь data в виде массива байтов.
  • ttl — время жизни push-уведомления типа Int в секундах.
  • from — поле, по которому можно понять, откуда пришло уведомление:
    • для уведомлений, отправленных в топик, в поле отображается имя топика;
    • в других случаях — часть вашего сервисного токена.
Структура объекта Notification
public class Notification {
public string title;
public string body;
public string channelId;
public string imageUrl;
public string color;
public string icon;
public string clickAction;
public ClickActionType? clickActionType;
}
  • 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
    .
  • clickActionintent action, с помощью которого будет открыта активити при клике на уведомление.
  • clickActionType — тип поля clickAction.
Перечисление ClickActionType
namespace RuStore.PushClient
{
public enum ClickActionType
{
DEFAULT,
DEEP_LINK,
}
}

Создание канала для отправки уведомления

Для канала, в который отправляется уведомление, действует следующий приоритет.

  • Если в push-уведомлении есть поле channelId, RuStore SDK отправит уведомление в указанный канал. Ваше приложение должно создать этот канал заранее.

  • Если в push-уведомлении нет поля channelId, но ваше приложение указало параметр с каналом в AndroidManifest.xml, используется указанный канал. Ваше приложение должно создать этот канал заранее.

  • Если в push-уведомлении нет поля channelId, и канал по умолчанию не задан в AndroidManifest.xml, RuStore SDK создаст канал и отправит уведомление в него. В дальнейшем все уведомления без явного указания канала будут отправляться в этот канал.

Обработка ошибок

Если вы получили в ответ Failure, не рекомендуется отображать ошибку пользователю. Отображение ошибки может негативно повлиять на пользовательский опыт.

Класс RuStoreError
namespace RuStore {

public class RuStoreError {

public string name;
public string description;
}
}
  • name — название ошибки. Содержит имя simpleName класса ошибки.
  • description — сообщение ошибки.

Если при инициализации SDK вы передали параметр allowNativeErrorHandling == true, в случае ошибки:

  • Вызовется соответствующий обработчик onFailure.

  • Ошибка передастся в метод resolveForPush нативного SDK. Это нужно, чтобы показать пользователю диалог с ошибкой.

Метод resolveForPush
fun RuStoreException.resolveForPush(context: Context)

Чтобы отключить передачу ошибки в нативный SDK, установите значение false для свойства AllowNativeErrorHandling.

Запрет нативной обработки ошибок
RuStorePushClient.Instance.AllowNativeErrorHandling = false;

Возможные ошибки

  • RuStoreNotInstalledException — на устройстве пользователя не установлен RuStore.

  • RuStoreOutdatedException — версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK.

  • RuStoreUserUnauthorizedException — пользователь не авторизован в RuStore.

  • RuStoreFeatureUnavailableException — RuStore не имеет разрешения на работу в фоне.

  • RuStoreException — базовая ошибка RuStore, от которой наследуются остальные ошибки.

См. также