SDK in-app платежей для Unreal Engine (версия 6.1.0)
RuStore позволяет интегрировать платежи в мобильное приложение.
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
Пример реализации
Ознакомьтесь с приложением-прим ером чтобы узнать, как правильно интегрировать SDK платежей.
Все операции с клиентом также доступны из Blueprints. Ниже представлен пример инициализации.

Условия работы платежей
- Загружены данные о приложении в разделе Push-уведомления > Проекты из Консоль RuStore.
Обратите внимание, что Billing SDK не поддерживает работу в ТВ-версии RuStore.
Приложение прошло модерацию (публиковать приложение необязательно).
.
- Подпись и package name различных типов сборок вашего приложения (debug, release и т.д.) могут отличаться друг от друга. В таком случае вы должны создать в разделе Push-уведомления > Проекты из Консоль RuStore проект под каждый тип сборки..
- Пользователь и приложение не должны быть заблокированы в RuStore.
Для приложения включена возможность покупок в RuStore Консоли.
.- Версия Unreal Engine 4.26 или выше.
Сервис имеет некоторые ограничения на работу за пределами России.
Подготовка к работе
- Скопируйте содержимое папки
Plugins
из официального репозитория RuStore на GitFlic в папкуPlugins
внутри своего проекта. - Перезапустите Unreal Engine.
- В списке плагинов (Edit > Plugins > Project > Mobile) отметьте плагины RuStoreBilling и RuStoreCore.
- Подключите модули модули
RuStoreCore
иRuStoreBilling
в файлеYourProject.Build.cs
в спискеPublicDependencyModuleNames
. - В настройках проекта (Edit > Project Settings > Android) установите параметр Minimum SDK Version на уровень не ниже 24 и параметр Target SDK Version не ниже 31.
Обработка deeplink
Для корректной работы оплаты через сторонние приложения (СБП, SberPay и др.) необходимо правильно реализовать обработку deeplink. Плагин RuStore Billing автоматически добавит в AndroidManifest.xml
дополнительную activity с необходимым intent-filter
(см. ниже). Изменить это поведение можно в файле RuStoreBilling_UPL_Android.xml
.
<activity android:name="com.Plugins.RuStoreBilling.RuStoreIntentFilterActivity" android:exported="true" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Set your appscheme -->
<data android:scheme="@string/rustore_app_scheme" />
</intent-filter>
</activity>
Вашему проекту необходимо реализовать наличие строкового ресурса @string/rustore_app_scheme
.
@string/rustore_app_scheme
— схема вашего deeplink. Эта схема должна совпадать со схемой deeplink, указываемой при инициализации библиотеки billing-клиента.
Инициализация
Перед вызовом методов библиотеки необходимо выполнить её инициализацию.
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = false;
URuStoreBillingClient::Instance()->Init(config);
Все операции с клиентом также доступны из Blueprints. Ниже представлен пример инициализации.

-
consoleApplicationId
— идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/
и/versions
. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versions
ID приложения —123456
.
-
deeplinkSheme
— URL-адрес для использования deeplink. В качестве названия может быть использовано любое уникальное имя (пример:yourappscheme
). -
allowNativeErrorHandling
— разрешить обработку ошибок в нативном SDK (см. подробнее в разделе Обработка ошибок). -
enableLogs
— включить ведение журнала событий.
Вызов Init()
привязывает объект к корню сцены, и если дальнейшая работа с объектом больше не планируется, для освобождения памяти необходимо выполнить метод Dispose()
.
Деинициализация
URuStoreBillingClient::Instance()->Dispose();

Проверка инициализации
Если вам нужно проверить факт инициализации библиотеки, используйте метод GetIsInitialized()
. Метод вернет true
, если библиотека инициализирована, и false
, если Init
еще не был вызван.
bool isInitialized = URuStoreBillingClient::Instance()->GetIsIninialized();

Как работают платежи
Проверка доступности работы с платежами
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
Для приложения включена возможность покупок в RuStore Консоли.
.
Метод устарел и не рекомендуется к использованию.
Для проверки доступности платежей используйте метод
CheckPurchasesAvailability
.
Каждый асинхронный запрос получает уникальный в рамках одного запуска приложения requestId
. Каждое событие возвращает requestId
запроса, породившего это событие.
long requestId = URuStoreBillingClient::Instance()->CheckPurchasesAvailability(
[]( long requestId, TSharedPtr<FURuStoreFeatureAvailabilityResult, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);

Уведомление обратного вызова (callback) Success
возвращает структуру FURuStoreFeatureAvailabilityResult
в параметре Response
(см. ниже).
USTRUCT(BlueprintType)
struct RUSTORECORE_API FURuStoreFeatureAvailabilityResult
{
GENERATED_USTRUCT_BODY()
FURuStoreFeatureAvailabilityResult()
{
isAvailable = false;
}
UPROPERTY(BlueprintReadWrite)
bool isAvailable;
UPROPERTY(BlueprintReadWrite)
FURuStoreError cause;
};
-
isAvailable
— выполнение условий выполнения платежей (true
/false
). -
cause
— информация об ошибке.
Все возможные ошибки cause
описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в Failure
.
Уведомление обратного вызова (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке в параметре Error
. Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.
Работа с SDK
Получение списка продуктов
Вы проверили, что платежи доступны и пользователи могут совершать покупки. Теперь можно получить список продуктов. Используйте метод GetProducts()
, чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
long requestId = URuStoreBillingClient::Instance()->GetProducts(
productsId,
[]( long requestId, TSharedPtr<FURuStoreProductsResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);

TArray<FString> productIds
— список идентификаторов продуктов. В нём не должно быть более 100 позиций.
Чтобы указать id
продуктов, которые нужны для работы метода, выполните следующие действия.
- Откройте RuStore Консоль.
- Перейдите на вкладку Приложения.
- Выберите нужное приложение.
- В левом боковом меню выберите раздел Монетизация.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров. Это и есть
id
продуктов.
Уведом ление обратного вызова (callback) Success
возвращает структуру FURuStoreProductsResponse
в параметре Response
(см. ниже).
Ответ GetProducts
USTRUCT(BlueprintType)
struct FURuStoreProductsResponse
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
TArray<FURuStoreProduct> products;
};
products
— список продуктов
Структура продукта
USTRUCT(BlueprintType)
struct FURuStoreProduct
{
GENERATED_USTRUCT_BODY()
FURuStoreProduct()
{
productId = "";
productType = EURuStoreProductType::NON_CONSUMABLE;
productStatus = EURuStoreProductStatus::INACTIVE;
priceLabel = "";
price = 0;
currency = "";
language = "";
title = "";
description = "";
imageUrl = "";
promoImageUrl = "";
}
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
EURuStoreProductType productType;
UPROPERTY(BlueprintReadOnly)
EURuStoreProductStatus productStatus;
UPROPERTY(BlueprintReadOnly)
FString priceLabel;
UPROPERTY(BlueprintReadOnly)
int price;
UPROPERTY(BlueprintReadOnly)
FString currency;
UPROPERTY(BlueprintReadOnly)
FString language;
UPROPERTY(BlueprintReadOnly)
FString title;
UPROPERTY(BlueprintReadOnly)
FString description;
UPROPERTY(BlueprintReadOnly)
FString imageUrl;
UPROPERTY(BlueprintReadOnly)
FString promoImageUrl;
UPROPERTY(BlueprintReadOnly)
FURuStoreProductSubscription subscription;
};
productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).productType
— тип продукта (потребляемый / непотребляемый / подписка):CONSUMABLE
/NON-CONSUMABE
/SUBSCRIPTION
.productStatus
— статус продукта.priceLable
— отформатированная цена товара, включая валютный знак на языкеlanguage
.price
— цена в минимальных единицах (в копейках).currency
— код валюты ISO 4217.language
— язык, указанный с помощью BCP 47 кодирования.title
— название продукта на языкеlanguage
.description
— описание на языкеlanguage
.imageUrl
— ссылка на картинку.promoImageUrl
— ссылка на промокартинку.subscription
— описание подписки, возвращается только для продуктов с типомsubscription
.
Тип продукта
UENUM(BlueprintType)
enum class EURuStoreProductType : uint8
{
NON_CONSUMABLE UMETA(DisplayName = "NON_CONSUMABLE"),
CONSUMABLE UMETA(DisplayName = "CONSUMABLE"),
SUBSCRIPTION UMETA(DisplayName = "SUBSCRIPTION")
};
Статус продукта
UENUM(BlueprintType)
enum class EURuStoreProductStatus : uint8
{
ACTIVE UMETA(DisplayName = "ACTIVE"),
INACTIVE UMETA(DisplayName = "INACTIVE")
};
Структура подписки
USTRUCT(BlueprintType)
struct FURuStoreProductSubscription
{
GENERATED_USTRUCT_BODY()
FURuStoreProductSubscription()
{
introductoryPrice = "";
introductoryPriceAmount = "";
}
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod subscriptionPeriod;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod freeTrialPeriod;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod gracePeriod;
UPROPERTY(BlueprintReadOnly)
FString introductoryPrice;
UPROPERTY(BlueprintReadOnly)
FString introductoryPriceAmount;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod introductoryPricePeriod;
};
subscriptionPeriod
— период подписки.freeTrialPeriod
— пробный период подписки.gracePeriod
— льготный период подписки.introductoryPrice
— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language
.introductoryPriceAmount
— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod
— расчётный период вступительной цены.
Структура для сроков периода подписки
USTRUCT(BlueprintType)
struct FURuStoreSubscriptionPeriod
{
GENERATED_USTRUCT_BODY()
FURuStoreSubscriptionPeriod()
{
years = 1970;
months = 1;
days = 1;
}
UPROPERTY(BlueprintReadOnly)
int years;
UPROPERTY(BlueprintReadOnly)
int months;
UPROPERTY(BlueprintReadOnly)
int days;
};
years
— количество лет.months
— количество месяцев.days
— количество дней.
Уведомление обратного вызова (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке в параметре Error
.
Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.
Покупка продукта
Для вызова покупки продукта используйте метод PurchaseProduct()
.
Вызов метода покупки продукта
long requestId = URuStoreBillingClient::Instance()->PurchaseProduct(
productId,
orderId,
quantity,
developerPayload,
[]( long requestId, TShardPtr<FURuStorePaymentResult, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);

productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).orderId: String
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.quantity
— количество продукта (необязательный параметр — если не указывать, будет использоваться значение1
).developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.
Уведомление обратного вызова (callback) Success
возвращает умный потокобезопасный (ESPMode::ThreadSafe
) указатель на объект наследника структуры FURuStorePaymentResult
в параметре Response
.
Тип объекта наследника можно получить используя метод GetTypeName()
. Приведение типа можно выполнить через StaticCastSharedPtr<>
.
// TShardPtr<FURuStorePaymentResult, ESPMode::ThreadSafe> response
FString typeName = response->GetTypeName();
if (typeName == "FURuStoreSuccess")
{
auto success = *StaticCastSharedPtr<FURuStoreSuccess>(response);
}
Возможные значения типов:
FURuStoreSuccess
— результат успешного завершения покупки цифрового товара.FURuStoreFailure
— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.FURuStoreCancelled
— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.FURuStoreInvalidPaymentState
— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.
В blueprint-реализаци уведомление обратного вызова (callback) Success
возвращает объект наследника класса URuStorePaymentResultClass
в параметре Response
. Приведение к типу наследника можно выполнить через каскад вызовов Cast To
.

Структура результата покупки
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStorePaymentResultClass : public UObject
{
GENERATED_BODY()
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
virtual ~FURuStorePaymentResult() {}
virtual FString GetTypeName() { return "FURuStorePaymentResult"; }
};
Структура результата покупки Success
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreSuccess : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreSuccess value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreSuccess : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
FURuStoreSuccess()
{
orderId = "";
purchaseId = "";
productId = "";
invoiceId = "";
subscriptionToken = "";
sandbox = false;
}
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString subscriptionToken;
UPROPERTY(BlueprintReadOnly)
bool sandbox;
virtual FString GetTypeName() override { return "FURuStoreSuccess"; }
};
Структура результата покупки Cancelled
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreCancelled : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreCancelled value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreCancelled : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
FURuStoreCancelled()
{
purchaseId = "";
sandbox = false;
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
bool sandbox;
virtual FString GetTypeName() override { return "FURuStoreCancelled"; }
};
Структура результата покупки Failure
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreFailure : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreFailure value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreFailure : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
public:
FURuStoreFailure()
{
purchaseId = "";
invoiceId = "";
orderId = "";
quantity = 0;
productId = "";
errorCode = 0;
sandbox = false;
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
int quantity;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
int errorCode;
UPROPERTY(BlueprintReadOnly)
bool sandbox;
virtual FString GetTypeName() override { return "FURuStoreFailure"; }
};
Параметр sandbox
определяет, является ли платёж тестовым. Значения могут быть true
или false
,
где true
обозначает тестовый платёж, а false
– реальный.
Структура результата покупки InvalidPaymentState
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreInvalidPaymentState : public URuStorePaymentResultBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreInvalidPaymentState value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreInvalidPaymentState : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
virtual FString GetTypeName() override { return "FURuStoreInvalidPaymentState"; }
};
Уведомление обратного вызова (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке в параметре Error
. Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.