SDK Платежи in-app для Unreal (версия 10.0.1)
RuStore позволяет интегрировать платежи в мобильное приложение.
-
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
-
Если вы переходите на Pay SDK с billingClient SDK, ознакомьтесь с инструкцией по переходу. Подробности о Pay SDK можно узнать тут.
Подготовка к работе
Поддерживаются версии Unreal Engine 4.26 и выше.
- Скопируйте проекты плагина и приложения-примера из официального репозитория RuStore на GitFlic.
- Скопируйте содержимое папки
unreal_example/Pluginsв папкуPluginsвнутри своего проекта. Перезапустите Unreal Engine. - В списке плагинов (Edit ➝ Plugins ➝ Mobile) отметьте плагины RuStorePay и RuStoreCore.
- В файле
YourProject.Build.csв спискеPublicDependencyModuleNamesподключите модулиRuStoreCoreиRuStorePay. - В настройках проекта (Edit ➝ Project Settings ➝ Android) установите параметры:
- Minimum SDK Version — не ниже 24;
- Target SDK Version — не ниже 34.
Инициализация SDK
Перед вызовом методов библиотеки необходимо выполнить её инициализацию.
URuStorePayClient::Instance()->Init();
Для работы SDK в вашем AndroidManifest.xml плагин RuStorePay через файл RuStorePay_UPL_Android.xml добавит в манифест приложения данные console_app_id_value, internal_config_key и sdk_pay_scheme_value. Все значения располагаются внутри тэга <application>.
<application>
...
<meta-data android:name="console_app_id_value" android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data android:name="internal_config_key" android:value="@string/rustore_PayClientSettings_internalConfigKey" />
<meta-data android:name="sdk_pay_scheme_value" android:value="@string/rustore_PayClientSettings_deeplinkScheme" />
</application>
-
console_app_id_key— идентификатор приложения из RuStore консоли. internal_config_key— всегда имеет значениеunreal-engine.sdk_pay_scheme_value— схема deeplink.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/и/versions. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versionsID приложения —123456.

Package Name приложения, указанный в Edit ➝ Project Settings... ➝ Player ➝ Android ➝ Other Settings ➝ Package Name, должен совпадать с Package Name APK-файла, который вы публиковали в системе RuStore Консоль.
Подпись keystore должна совпадать с подписью, которой было подписано приложение, опубликованное в системе RuStore Консоль. Убедитесь, что используемый buildType (пр. debug) использует такую же подпись, что и опубликованное приложение (пр. release).
Все значения должны быть заданы в файле ресурсов, например: rustore_pay_values.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="rustore_PayClientSettings_consoleApplicationId">198332</string>
<string name="rustore_PayClientSettings_internalConfigKey" translatable="false">unreal-engine</string>
<string name="rustore_PayClientSettings_deeplinkScheme" translatable="false">yourappscheme</string>
</resources>
Файл ресурсов может быть включен в проект через UPL-файл вашего проекта, в следующем примере копирование файла rustore_pay_values.xml в ресурсы сборки Android будет выполняться из директории Source/YOUR_PROJECT_NAME.
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:android="http://schemas.android.com/apk/res/android">
<resourceCopies>
<copyFile src="$S(PluginDir)/rustore_pay_values.xml" dst="$S(BuildDir)/res/values/rustore_pay_values.xml" />
</resourceCopies>
</root>
Деинициализация SDK
Вызов метода Init для URuStorePayClient привязывает объекты к корню сцены. Если дальнейшая работа с объектами больше не планируется, для освобождения памяти необходимо выполнить метод Dispose. Вызов Dispose отвяжет объект от корня и безопасно завершит все отправленные запросы.
bool isInitialized = URuStorePayClient::Instance()->Dispose();
Проверка инициализации SDK
Если вам нужно проверить факт инициализации библиотеки, используйте метод GetIsInitialized. Метод вернет true, если библиотека инициализирована, и false, если Init еще не был вызван.
bool isInitialized = URuStorePayClient::Instance()->GetIsIninialized();
Обработка deeplink
Deeplink в RuStore SDK платежей нужна для корректной работы со сторонними приложениями оплаты. Она помогает пользователям быстрее совершать покупки в стороннем приложении и возвращаться в ваше приложение.
Допускаются только символы в кодировке ASCII. Формат должен соответствовать спецификации RFC-3986.
Плагин RuStore Pay автоматически изменит AndroidManifest.xml:
- Удалит запускающий
intent-filterуGameActivityилиSplashActivity. - Добавит дополнительную активити
RuStorePayIntentFilterActivityсintent-filterдля запуска приложения и обработки deeplink.
Изменить это поведение можно в файле RuStorePay_UPL_Android.xml.
<!-- Deeplink activity -->
<activity android:name="com.Plugins.RuStorePay.RuStorePayIntentFilterActivity"
android:theme="@android:style/Theme.NoDisplay"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Deeplink scheme -->
<data android:scheme="@string/rustore_PayClientSettings_deeplinkScheme" />
</intent-filter>
</activity>
Реализация RuStorePayIntentFilterActivity
package com.Plugins.RuStorePay;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import ru.rustore.unrealsdk.payclient.RuStoreUnrealPayClient;
public class RuStorePayIntentFilterActivity extends Activity {
private String[] ueActivitieNames = {
"com.epicgames.ue4.SplashActivity",
"com.epicgames.ue4.GameActivity",
"com.epicgames.unreal.SplashActivity",
"com.epicgames.unreal.GameActivity"
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreUnrealPayClient.INSTANCE.proceedIntent(getIntent());
}
if (!isTaskRoot()) {
finish();
return;
}
startUEActivity(ueActivitieNames);
finish();
}
@Override
public void onNewIntent(Intent newIntent) {
super.onNewIntent(newIntent);
RuStoreUnrealPayClient.INSTANCE.proceedIntent(newIntent);
}
private void startUEActivity(String[] ueActivitieNames) {
String ueActivityClassName = findActivityClassName(ueActivitieNames);
Class<?> ueActivityClass = getActivityClass(ueActivityClassName);
if (ueActivityClass != null) {
Intent intent = new Intent(this, ueActivityClass);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
}
private String findActivityClassName(String[] findActivitieNames) {
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(
getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : packageInfo.activities) {
String activityInfoName = activityInfo.name;
for (String findActivityName : findActivitieNames) {
if (activityInfoName.equals(findActivityName)) {
return activityInfoName;
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
private Class<?> getActivityClass(String activityClassName) {
try {
return Class.forName(activityClassName);
} catch(ClassNotFoundException ex) {
return null;
}
}
}
Метод proceedIntent имеет перегрузку с дополнительным параметром maxRetryTimeMs: Long.
long maxRetryTimeMs = 5000L;
RuStoreUnityPayClient.INSTANCE.proceedIntent(intent, maxRetryTimeMs);
maxRetryTimeMs— максимальное время (в миллисекундах) для повторных попыток инициализации платёжного клиента (по умолчанию 5000 мс).
Методы SDK
Проверка доступности работы с платежами
Для проверки доступности платежей, вызовите метод GetPurchaseAvailability. При его вызове проверяются следующие условия.
- У компании подключена монетизация через консоль разработчика RuStore.
- Приложение не должно быть заблокировано в RuStore.
- Пользователь не должен быть заблокирован в RuStore.
PurchaseAvailabilityResult.Available.
В противном случае возвращается PurchaseAvailabilityResult.Unavailable(val cause: Throwable), где cause — это ошибка о невыполненном условии. Для проверки причины возвращения такого результата нужно проверить тип ошибки на RuStoreException (данные ошибки описаны в разделе Обработка ошибок).
long requestId = URuStorePayClient::Instance()->GetPurchaseAvailability(
[](long requestId, TSharedPtr<FURuStorePayPurchaseAvailabilityResult, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Проверка статуса авторизации пользователя
Для проверки статуса авторизации пользователя, вызовите метод GetUserAuthorizationStatus. Результатом выполнения метода является значение перечисления UserAuthorizationStatus. Возможно только 2 значения:
AUTHORIZED— пользователь авторизован в RuStore.UNAUTHORIZED— пользователь неавторизован в RuStore. Данное значение также вернется если у пользователя нет установленного МП RuStore на девайсе.
RuStorePayClient.Instance.GetUserAuthorizationStatus(
onSuccess: (result) => {
if (result == UserAuthorizationStatus.AUTHORIZED) {
// Process result
}
});
onFailure: (error) => {
// Process error
},
Получение списка продуктов
Для получения продуктов, добавленных в ваше приложение через RuStore консоль, необходимо использовать метод GetProducts.
TArray<URuStorePayProductId*> productIds;
long requestId = URuStorePayClient::Instance()->GetProducts(
productsId,
[](long requestId, TSharedPtr<TArray<FURuStorePayProduct>, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
TArray<URuStorePayProductId*> productIds — список идентификаторов продуктов (задаются при создании продукта в консоли разработчика). Список продуктов имеет ограничение в размере 1000 элементов.
Где в RuStore Консоль отображаются идентификаторы продуктов?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Выберите Монетизация в меню слева.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров.

Метод возвращает список продуктов. Ниже представлена модель продукта.
USTRUCT(BlueprintType)
struct FURuStorePayProduct
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayAmountLabel* amountLabel;
UPROPERTY(BlueprintReadOnly)
URuStorePayCurrency* currency;
UPROPERTY(BlueprintReadOnly)
URuStorePayDescription* description; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayUrl* imageUrl;
UPROPERTY(BlueprintReadOnly)
URuStorePayPrice* price; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
URuStorePayTitle* title;
UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType type;
FURuStorePayProduct()
{
amountLabel = NewObject<URuStorePayAmountLabel>();
currency = NewObject<URuStorePayCurrency>();
description = nullptr;
imageUrl = NewObject<URuStorePayUrl>();
price = nullptr;
productId = NewObject<URuStorePayProductId>();
title = NewObject<URuStorePayTitle>();
type = static_cast<EURuStorePayProductType>(0);
}
};
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).type— тип продукта.CONSUMABLE/NON-CONSUMABLE/SUBSCRIPTION(потребляемый/непотребляемый/подписка).amountLabel— отформатированная цена покупки, включая валютный знак.price— цена в минимальных единицах (в копейках).currency— код валюты ISO 4217.title— название продукта на языкеlanguage.description— описание на языкеlanguage.imageUrl— ссылка на картинку.subscriptionInfo— информация о подписке (будет неnull, если тип продуктаSUBSCRIPTION).
Получение списка покупок
Для получения списка покупок пользователя используйте метод GetPurchases.
long requestId = URuStorePayClient::Instance()->GetPurchases(
[](long requestId, TSharedPtr<TArray<FURuStorePayPurchase>, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Данный метод позволяет фильтровать покупки по типу товаров и статусу покупки:
Типы товаров:
- Потребляемые товары —
EURuStorePayProductType::CONSUMABLE_PRODUCT - Непотребляемые товары —
EURuStorePayProductType::NON_CONSUMABLE_PRODUCT - Подписки —
EURuStorePayProductType::SUBSCRIPTION
Статусы покупок:
-
Для продуктов:
PAID: Успешное холдирование средств, покупка ожидает подтверждения со стороны разработчика.CONFIRMED: Покупка подтверждена, средства списаны.
-
Для подписок:
ACTIVE: Подписка активна.PAUSED: Подписка в Hold периоде (например, из-за недостатка средств на карте), продолжаются попытки списания в соответствии с настройками тарифа подписки.
По умолчанию фильтры выключены, если значения не заданы, метод вернёт все покупки пользователя в статусах PAID, CONFIRMED, ACTIVE и PAUSED, независимо от типа товара.
bool bUseProductType = true;
bool bUsePurchaseStatusFilter = true;
EURuStorePayProductType productType = EURuStorePayProductType::CONSUMABLE_PRODUCT;
EURuStorePayPurchaseStatusFilter purchaseStatusFilter = EURuStorePayPurchaseStatusFilter::CONFIRMED;
long requestId = URuStorePayClient::Instance()->GetPurchases(
bUseProductType,
bUsePurchaseStatusFilter,
productType,
purchaseStatusFilter,
[](long requestId, TSharedPtr<TArray<FURuStorePayPurchase>, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Получение сведений о покупке
Для получения информации о покупке, используйте методGetPurchase.
URuStorePayPurchaseId* purchaseId = ...
long requestId = URuStorePushClient::Instance()->GetPurchase(
purchaseId,
[](long requestId, TSharedPtr<FURuStorePayPurchase, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Метод возвращает информацию о конкретной покупке в любом статусе.
Типы покупок
В SDK предусмотрена базовая структуру FURuStorePayPurchase, которая объединяет общие поля всех типов покупок.
Структура также включает:
- productPurchase — дополнительные поля для потребляемых и непотребляемых покупок.
- subscriptionPurchase — дополнительные поля для подписок.
USTRUCT(BlueprintType)
struct FURuStorePayPurchase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType productType;
UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;
UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId;
UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseType purchaseType;
UPROPERTY(BlueprintReadOnly)
URuStorePayDescription* description;
UPROPERTY(BlueprintReadOnly)
URuStorePayDate* purchaseTime;
UPROPERTY(BlueprintReadOnly)
URuStorePayPrice* price;
UPROPERTY(BlueprintReadOnly)
URuStorePayAmountLabel* amountLabel;
UPROPERTY(BlueprintReadOnly)
URuStorePayCurrency* currency;
UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload;
UPROPERTY(BlueprintReadOnly)
bool sandbox;
UPROPERTY(BlueprintReadOnly)
FURuStorePayProductPurchase productPurchase;
UPROPERTY(BlueprintReadOnly)
FURuStorePaySubscriptionPurchase subscriptionPurchase;
FURuStorePayPurchase()
{
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
productType = static_cast<EURuStorePayProductType>(0);
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
orderId = nullptr;
purchaseType = static_cast<EURuStorePayPurchaseType>(0);
description = NewObject<URuStorePayDescription>(GetTransientPackage());
purchaseTime = nullptr;
price = NewObject<URuStorePayPrice>(GetTransientPackage());
amountLabel = NewObject<URuStorePayAmountLabel>(GetTransientPackage());
currency = NewObject<URuStorePayCurrency>(GetTransientPackage());
developerPayload = nullptr;
sandbox = false;
}
};
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр). Идентификатор продукта, который был присвоен продукту в RuStore Консоли.productType— тип продукта. (NON_CONSUMABLE/CONSUMABLE/SUBSCRIPTION— непотребляемый/потребляемый/подписка.)purchaseId— идентификатор покупки. Идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупке.invoiceId— идентификатор счёта. Идентификатор счёта. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей в мобильном приложении RuStore.orderId- уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).purchaseType— тип покупки:ONE_STEP- одностадийная покупка;TWO_STEP- двухстадийная покупка;UNDEFINED- стадийность не определена.
description— описание покупки.purchaseTime— время покупки.price— цена в минимальных единицах (в копейках).amountLabel— отформатированная цена покупки, включая валютный знак.currency— код валюты ISO 4217.-
developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации -
sandbox— флаг тестового платежа. Значениеtrue— тестовый платёж,false— реальный платёж. productPurchase— специфичные данные продукта.subscriptionPurchase— специфичные данные подписки.
Модель разовой покупки FURuStorePayProductPurchase
USTRUCT(BlueprintType)
struct FURuStorePayProductPurchase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
EURuStorePayProductPurchaseStatus status;
UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;
FURuStorePayProductPurchase()
{
status = static_cast<EURuStorePayProductPurchaseStatus>(0);
quantity = NewObject<URuStorePayQuantity>(GetTransientPackage());
}
};
status— состояние покупки:INVOICE_CREATED— создан счёт на оплату, покупка ожидает оплаты;CANCELLED— покупка отменена покупателем;PROCESSING— запущена оплата;REJECTED— покупка отклонена (например, ввиду недостатка средств);CONFIRMED— покупка успешно оплачена;REFUNDED— запрос на возврат средств за покупку совершён успешно. Деньги будут возвращены пользователю в течение 10 рабочих дней.;REFUNDING— инициирован возврат средств, запрос отправлен в эквайер;EXECUTING— покупка находится в процессе выполнения;EXPIRED— истекло время на оплату покупки;PAID— только для двухстадийной оплаты, промежуточный статус, средства на счёте покупателя захолдированы, покупка ожидает подтверждения от разработчика;REVERSED— только для двухстадийной оплаты, покупка была отменена разработчиком или не было произведено подтверждение покупки в течение 6 часов, холдирование средств отменено.
quantity— количество продукта.
Статусная модель покупки
Статусная модель одностадийного платежа.
Статусная модель двухстадийного платежа.
Модель подписки FURuStorePaySubscriptionPurchase
USTRUCT(BlueprintType)
struct FURuStorePaySubscriptionPurchase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
EURuStorePaySubscriptionPurchaseStatus status;
UPROPERTY(BlueprintReadOnly)
URuStorePayDate* expirationDate;
UPROPERTY(BlueprintReadOnly)
bool gracePeriodEnabled;
FURuStorePaySubscriptionPurchase()
{
status = static_cast<EURuStorePaySubscriptionPurchaseStatus>(0);
expirationDate = NewObject<URuStorePayDate>(GetTransientPackage());
gracePeriodEnabled = false;
}
};
status- состояние подписки:INVOICE_CREATED— создан счет на оплату, подписка ожидает оплаты.CANCELLED— счет на оплату подписки отменен.EXPIRED— срок действия оплаты счета истек.PROCESSING— первый платеж по подписке в обработке.REJECTED— первый платеж по подписке отклонен. Подписка не оформлена.ACTIVE— подписка активна.PAUSED— подписка приостановлена из-за проблем с оплатой.TERMINATED— закончились попытки списания по подписке (все были неуспешными). Подписка закрыта автоматически из-за проблем с оплатой.CLOSED— подписка была отменена пользователем или разработчиком. Истек срок оплаченного периода, подписка закрыта.
expirationDate— дата окончания действия подписки.gracePeriodEnabled— флаг, указывающий, активен ли Grace-период для подписки.
Статусная модель подписки
Покупка продукта
- При использовании одностадийного платежа покупка не требует подтверждения, денежные средства сразу списываются со счёта покупателя, а с разработчика удерживается комиссия. В таком случае, если требуется вернуть денежные средства клиенту (например, по какой-то причине нет возможности поставить продукт), возможен только возврат средств через RuStore Консоль, денежные средства возвращаются покупателю через несколько дней. Возвращается полная стоимость покупки, при этом удержанная комиссия разработ чику не возмещается.
- В случае использования двухстадийного платежа сначала производится холдирование средств на счете покупателя. Комиссия в этом случае не удерживается. После холдирования покупка требует подтверждения или отмены. Комиссия с разработчика удерживается при подтверждении покупки. Отмена покупки означает снятие холда - денежные средства мгновенно снова доступны покупателю.
Двухстадийная оплата доступна только для определенного набора способов оплаты (на текущий момент — только для карт и SberPay). Технологии СБП не поддерживают двухстадийную оплату. Если выбран способ оплаты, который не поддерживает холдирование, то покупка будет запущена по сценарию с одной стадией.
Оплата с выбором типа покупки
Для вызова покупки продукта с выбором стадийности оплаты используйте метод Purchase:
FURuStorePayProductPurchaseParams productPurchaseParams;
EURuStorePayPreferredPurchaseType preferredPurchaseType;
...
long requestId = URuStorePayClient::Instance()->Purchase(
productPurchaseParams,
preferredPurchaseType,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются.-
appUserId— внутренний ID пользователя в вашем приложении (опциональный параметр). Строка с максимальной длиной в 128 символов.подсказкаНапример, данный параметр может использоваться для выявления случаев мошенничества в вашем приложении, что позволит повысить его безопасность.
appUserEmail- это необязательный параметр, позволяющий задать адрес электронной почты пользователя в вашем приложении. Если адрес электронной почты покупателя был указан при регистрации в приложении, его можно передать для автоматического заполнения поляemailпри отправке чека — как для платежей вне RuStore, так и для случаев, когда пользователь не авторизован в RuStore. Это избавляет пользователя от необходимости вручную вводить email, сокращает путь до покупки и способствует повышению конверсии.preferredPurchaseType— желаемый тип покупки: одностадийная (ONE_STEP) или двухстадийная (TWO_STEP).
Данный метод по умолчанию запускается по одностадийному сценарию оплаты (preferredPurchaseType = PreferredPurchaseType.ONE_STEP), т.е. без холдирования средств.
Для двухстадийной оплаты нужно указать preferredPurchaseType = PreferredPurchaseType.TWO_STEP. Двухстадийная оплата (т.е. оплата с холдированием средств) для данного метода не гарантирована и напрямую зависит от того, какой способ оплаты (карта, СПБ и др.) выбрал пользователь.
При запуске данного метода (с предпочитаемым preferredPurchaseType = twoStep), до тех пор пока пользователь не выберет способ оплаты, стадийность покупки будет UNDEFINED. Учитывайте данное поведение при обработке результатов отмены (ProductPurchaseCancelled) или ошибки (ProductPurchaseException) покупки.
Двухстадийная оплата (с холдированием средств)
FURuStorePayProductPurchaseParams productPurchaseParams;
...
long requestId = URuStorePushClient::Instance()->PurchaseTwoStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Структура параметров покупки:
USTRUCT(BlueprintType)
struct FURuStorePayProductPurchaseParams
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
URuStorePayAppUserEmail* appUserEmail; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayAppUserId* appUserId; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity; // nullable
FURuStorePayProductPurchaseParams()
{
productId = NewObject<URuStorePayProductId>();
appUserEmail = nullptr;
appUserId = nullptr;
developerPayload = nullptr;
orderId = nullptr;
quantity = nullptr;
}
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются.-
appUserId— внутренний ID пользователя в вашем приложении (опциональный параметр). Строка с максимальной длиной в 128 символов.подсказкаНапример, данный параметр может использоваться для выявления случаев мошенничества в вашем приложении, что позволит повысить его безопасность.
appUserEmail— это необязательный параметр, позволяющий задать адрес электронной почты пользователя в вашем приложении. Если адрес электронной почты покупателя был указан при регистрации в приложении, его можно передать для автоматического заполнения поляemailпри отправке чека — как для платежей вне RuStore, так и для случаев, когда пользователь не авторизован в RuStore. Это избавляет пользователя от необходимости вручную вводить email, сокращает путь до покупки и способствует повышению конверсии.
Структура результата покупки
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType productType;
UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;
UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseType purchaseType;
UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;
UPROPERTY(BlueprintReadOnly)
bool sandbox;
FURuStorePayProductPurchaseResult()
{
orderId = nullptr;
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
productType = static_cast<EURuStorePayProductType>(0);
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
purchaseType = static_cast<EURuStorePayPurchaseType>(0);
quantity = NewObject<URuStorePayQuantity>(GetTransientPackage());
sandbox = false;
}
};
FURuStorePayProductPurchaseResult— результат успешной оплаты цифрового товара (для одностадийной оплаты) или успешного холдирования средств (для двухстадийной оплаты).purchaseId— идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупкеproductId— идентификатор приобретенного продукта, указанный при создании в консоли разработчика RuStore.productType— тип продукта. (NON_CONSUMABLE/CONSUMABLE/SUBSCRIPTION— непотребляемый/потребляемый/подписка.)invoiceId— идентификатор счета. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей в мобильном приложении RuStoreorderId— уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).purchaseType— тип покупки (ONE_STEP/TWO_STEP/UNDEFINED— одностадийная/двухстадийная/стадийность не определена).quantity— количество купленного продукта.sandbox— флаг, указывающий признак тестового пл атежа в песочнице. ЕслиTRUE- покупка совершена в режиме тестирования.
Обработка ошибки оплаты
Если в процессе оплаты возникает ошибка или пользователь отменяет покупку, выполнение метода оплаты (как с выбором типа покупки, так и двухстадийного метода) завершается с ошибкой:
ProductPurchaseCancelled— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.ProductPurchaseException— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.
Структура ошибки FURuStoreError описана в разделе Обработка ошибок.
Серверная валидации покупки
Если вам необходимо произвести валидацию успешной покупки на сервере RuStore, вы можете использовать invoiceId из модели SuccessProductPurchaseResult, возвращаемой при успешной покупке продукта.
long requestId = URuStorePushClient::Instance()->PurchaseTwoStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
auto type = response->GetTypeName();
if (type.Equals("FURuStorePaySuccessProductPurchaseResult")) {
auto success = *StaticCastSharedPtr<FURuStorePaySuccessProductPurchaseResult>(response);
FString invoiceId = success.invoiceId->value;
yourApi.validate(invoiceId);
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);