Перейти к основному содержимому

7.0.0

RuStore позволяет интегрировать платежи в мобильное приложение.

подсказка

Если не знаете с чего начать, прочтите инструкцию в сценариях использования.

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

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

Все операции с клиентом также доступны из Blueprints. Ниже представлен пример инициализации.

img

Условия работы платежей

  • Приложение загружено в Консоль RuStore.
  • Приложение прошло модерацию (публиковать приложение необязательно).
Важно
  • Подпись тестируемой сборки (например, debug) приложения должна совпадать с подписью сборки приложения, которая была загружена в консоль и прошла модерацию ранее (например, release).
  • Пользователь и приложение не должны быть заблокированы в RuStore.
  • Для приложения включена возможность покупок в RuStore Консоли.
  • Версия Unreal Engine 4.26 или выше.
предупреждение

Сервис имеет некоторые ограничения на работу за пределами России.

Подготовка к работе

  1. Скопируйте содержимое папки Plugins из официального репозитория RuStore на GitFlic в папку Plugins внутри своего проекта.
  2. Перезапустите Unreal Engine.
  3. В списке плагинов (Edit > Plugins > Project > Mobile) отметьте плагины RuStoreBilling и RuStoreCore.
  4. Подключите модули модули RuStoreCore и RuStoreBilling в файле YourProject.Build.cs в списке PublicDependencyModuleNames.
  5. В настройках проекта (Edit > Project Settings > Android) установите параметр Minimum SDK Version на уровень не ниже 24 и параметр Target SDK Version не ниже 31.

Для корректной работы оплаты через сторонние приложения (СБП, SberPay и др.) необходимо правильно реализовать обработку deeplink. Плагин RuStore Billing автоматически добавит в AndroidManifest.xml дополнительную activity с необходимым intent-filter (см. ниже). Изменить это поведение можно в файле RuStoreBilling_UPL_Android.xml.

AndroidManifest.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-клиента.

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

Перед вызовом методов библиотеки необходимо выполнить её инициализацию.

Вызов метода Init
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = false;

URuStoreBillingClient::Instance()->Init(config);

Все операции с клиентом также доступны из Blueprints. Ниже представлен пример инициализации.

img
Где в RuStore Консоль отображаются идентификаторы приложений?
  1. Перейдите на вкладку Приложения и выберите нужное приложение.
  2. Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между apps/ и /versions. Например, для URL-адреса https://console.rustore.ru/apps/123456/versions ID приложения — 123456.

  • deeplinkSheme — URL-адрес для использования deeplink. В качестве названия может быть использовано любое уникальное имя (пример: yourappscheme).
  • allowNativeErrorHandling — разрешить обработку ошибок в нативном SDK (см. подробнее в разделе Обработка ошибок).
  • enableLogs — включить ведение журнала событий.

Вызов Init() привязывает объект к корню сцены, и если дальнейшая работа с объектом больше не планируется, для освобождения памяти необходимо выполнить метод Dispose().

Деинициализация

Вызов метода Dispose
URuStoreBillingClient::Instance()->Dispose();
img

Проверка инициализации

Если вам нужно проверить факт инициализации библиотеки, используйте метод GetIsInitialized(). Метод вернет true, если библиотека инициализирована, и false, если Init еще не был вызван.

Вызов метода GetIsIninialized
bool isInitialized = URuStoreBillingClient::Instance()->GetIsIninialized();
img

Как работают платежи

Приложение для оплаты RuStore Сервер RuStore_Billing_Client Ваш сервер Ваше приложение Покупатель Приложение для оплаты RuStore Сервер RuStore_Billing_Client Ваш сервер Ваше приложение ПокупательПроверка доступности работы платежей [Необязательно] Серверная валидация платежа [Обязательно] Покупка потребляемого товара [Обязательно] Обработка deeplink при оплате СБП, SberPay и т.д.Покупка продукта Входит в ваше приложение checkPurchasesAvailability Результат getProducts Список продуктов вашего приложения Показ списка доступных покупок Приобретение товара purchaseProduct Запрос способа оплаты Проведение платежа Способ оплаты Результат проведения платежа Информация о платеже Серверная валидация (public API) Достоверная информация о покупке Начисление товара покупателю Резул�ьтат валидации confirmPurchase Результат потребления purchaseProduct Запрос способа оплаты Указал СБП/SberPay/T-Pay Запуск процесса оплаты Сценарий оплаты Оплата покупки Возврат в приложение OnNewIntent Результат оплаты Отображение платёжной шторки с результатом оплаты

Проверка доступности работы с платежами

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

  • На устройстве пользователя установлена актуальная версия RuStore.
  • Приложение RuStore поддерживает функциональность платежей.
  • Пользователь авторизован в RuStore.
  • Пользователь и приложение не должны быть заблокированы в RuStore.
  • Для приложения включена возможность покупок в RuStore Консоли.

Для проверки доступности платежей используйте метод CheckPurchasesAvailability.

Каждый асинхронный запрос получает уникальный в рамках одного запуска приложения requestId. Каждое событие возвращает requestId запроса, породившего это событие.

Вызов метода CheckPurchasesAvailability
long requestId = URuStoreBillingClient::Instance()->CheckPurchasesAvailability( 
[]( long requestId, TSharedPtr<FURuStoreFeatureAvailabilityResult, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

Уведомление обратного вызова (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 описана в разделе Обработка ошибок.

Проверка установки приложения RuStore

Чтобы проверить установлен ли на устройстве пользователя RuStore необходимо вызвать метод IsRuStoreInstalled.

bool bIsRuStoreInstalled = URuStoreBillingClient::Instance()->IsRuStoreInstalled();
img
  • true – RuStore установлен.

  • false – RuStore не установлен.

Работа с SDK

Получение списка продуктов

Вы проверили, что платежи доступны и пользователи могут совершать покупки. Теперь можно получить список продуктов. Используйте метод GetProducts(), чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.

Вызов метода GetProducts
long requestId = URuStoreBillingClient::Instance()->GetProducts(
productIds,
[]( long requestId, TSharedPtr<FURuStoreProductsResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

TArray<FString> productIds — список идентификаторов продуктов. В нём не должно быть более 100 позиций.

Чтобы указать id продуктов, которые нужны для работы метода, выполните следующие действия.

  1. Откройте RuStore Консоль.
  2. Перейдите на вкладку Приложения.
  3. Выберите нужное приложение.
  4. В левом боковом меню выберите раздел Монетизация.
  5. Выберите тип товара: Подписки или Разовые покупки.
  6. Скопируйте идентификаторы нужных товаров. Это и есть 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().

Вызов метода покупки продукта

Вызов метода 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
}
);
img
  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).
  • orderId: String — уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.
  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.

Уведомление обратного вызова (callback) Success возвращает умный потокобезопасный (ESPMode::ThreadSafe) указатель на объект наследника структуры FURuStorePaymentResult в параметре Response.

Тип объекта наследника можно получить используя метод GetTypeName(). Приведение типа можно выполнить через StaticCastSharedPtr<>.

Вызов методов 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.

img

Структура результата покупки

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 описана в разделе Обработка ошибок.

Получение списка покупок

Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.

Тип/СтатусINVOICE_CREATEDCONFIRMEDPAID
CONSUMABLE++
NON-CONSUMABLE++
SUBSCRIPTION++
примечание

Метод возвращает незавершённые состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтверждённые покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.

Для получения списка покупок пользователя используйте метод GetPurchases().

Вызов метода GetPurchases
long requestId = URuStoreBillingClient::Instance()->GetPurchases(
[]( long requestId, TSharedPtr<FURuStorePurchasesResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

Уведомление обратного вызова (callback) Success возвращает структуру FURuStorePurchasesResponse в параметре Response (см. ниже).

Ответ GetPurchases

USTRUCT(BlueprintType)
struct FURuStorePurchasesResponse: public FURuStoreResponseWithCode
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
TArray<FURuStorePurchase> purchases;
};

purchases — список запрошенных покупок

Структура покупки

USTRUCT(BlueprintType)
struct FURuStorePurchase
{
GENERATED_USTRUCT_BODY()

FURuStorePurchase()
{
purchaseId = "";
productId = "";
invoiceId = "";
language = "";
purchaseTime = FDateTime(0);
orderId = "";
amountLabel = "";
amount = 0;
currency = "";
quantity = 0;
purchaseState = EURuStorePurchaseState::CANCELLED;
developerPayload = "";
subscriptionToken = "";
}

UPROPERTY(BlueprintReadOnly)
FString purchaseId;

UPROPERTY(BlueprintReadOnly)
FString productId;

UPROPERTY(BlueprintReadOnly)
FString invoiceId;

UPROPERTY(BlueprintReadOnly)
FString language;

UPROPERTY(BlueprintReadOnly)
FDateTime purchaseTime;

UPROPERTY(BlueprintReadOnly)
FString purchaseTimeLabel;

UPROPERTY(BlueprintReadOnly)
FString orderId;

UPROPERTY(BlueprintReadOnly)
FString amountLabel;

UPROPERTY(BlueprintReadOnly)
int amount;

UPROPERTY(BlueprintReadOnly)
FString currency;

UPROPERTY(BlueprintReadOnly)
int quantity;

UPROPERTY(BlueprintReadOnly)
EURuStorePurchaseState purchaseState;

UPROPERTY(BlueprintReadOnly)
FString developerPayload;

UPROPERTY(BlueprintReadOnly)
FString subscriptionToken;
};

Состояние покупки

UENUM(BlueprintType)
enum class EURuStorePurchaseState : uint8
{
CREATED UMETA(DisplayName = "CREATED"),
INVOICE_CREATED UMETA(DisplayName = "INVOICE_CREATED"),
CONFIRMED UMETA(DisplayName = "CONFIRMED"),
PAID UMETA(DisplayName = "PAID UMETA"),
CANCELLED UMETA(DisplayName = "CANCELLED"),
CONSUMED UMETA(DisplayName = "CONSUMED"),
PAUSED UMETA(DisplayName = "PAUSED"),
CLOSED UMETA(DisplayName = "CLOSED")
};
  • purchaseId — идентификатор покупки.

  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).

  • invoiceId — идентификатор счёта.

  • language — язык, указанный с помощью BCP 47 кодирования.

  • purchaseTime — время покупки.

  • orderId — уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.

  • amountLable — отформатированная цена покупки, включая валютный знак.

  • amount — цена в минимальных единицах валюты.

  • currency — код валюты ISO 4217.

  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).

  • purchaseState — состояние покупки:

    • CREATED — покупка создана;
    • INVOICE_CREATED — по покупке создан счёт, ожидает оплаты;
    • PAID — только покупки потребляемого товара — промежуточный статус, средства на счёте покупателя зарезервированы. Покупка ожидает подтверждения от разработчика;
    • CONFIRMED — платеж за непотребляемый товар успешно совершен;
    • CONSUMED — платеж за потребляемый товар успешно совершен;
    • CANCELLED — покупка отменена — оплата не была произведена или был совершен возврат средств покупателю (для подписок после возврата средств покупка не переходит в CANCELLED);
    • PAUSED — для подписок — подписка перешла в HOLD период;
    • TERMINATED — подписка закрылась.
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.

  • subscriptionToken — токен для валидации покупки на сервере.

Обратный вызов (callback) Failure возвращает структуру FURuStoreError с информацией об ошибке в параметре Error.

Структура ошибки FURuStoreError описана в разделе Обработка ошибок.

Получение сведений о покупке

Для получения информации о покупке, используйте метод GetPurchaseInfo.
long requestId = URuStoreBillingClient::Instance()->GetPurchaseInfo(
purchaseId,
[]( long requestId, TSharedPtr<FURuStorePurchaseInfoResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

purchaseId — идентификатор покупки

Уведомление обратного вызова (callback) Success возвращает структуру FURuStorePurchase в параметре Response.

Уведомление обратного вызова (callback) Failure возвращает структуру FURuStoreError с информацией об ошибке. Структура ошибки FURuStoreError описана в разделе Обработка ошибок.

Статусная модель (purchaseState)

Статусная модель покупки потребляемых продуктов (CONSUMABLES)

Покупка создана, но счёт на оплату ещё не созданОплаты еще не было. Можно игнорировать такую покупку.У пользователя есть незавершенная покупка. Счёт создан, но не оплачен. Необходимо предупредить пользователя.Покупка отмененаДля продуктов типа consumable. Покупка оплачена, но не потреблена. Апу Арр должен немедленно отправить запрос на приобретение покупки.Для продуктов типа consumable. Потребление покупки было подтверждено.CREATEDINVOICE_CREATEDСANCELLEDСчёт созданСчёт оплаченПотреблениеPAIDCONSUMEDСчёт отменёнВозврат по счётуПокупка отменена / не потреблена в течение 72 часовПокупка отменена

Статусная модель покупки непотребляемых продуктов (NON-CONSUMABLES)

Покупка создана, но счёт на оплату еще не создан. Оплаты еще не было. Можно игнорировать такую покупку.У пользователя есть незавершенная покупка. Счёт создан, но не оплачен. Необходимо предупредить пользователя.Покупка отмененаСтатус завершения покупки для продуктов типа non-consumable или subscription. Означает, что товар уже приобретен, повторная попытка покупки приведет к ошибке.CREATEDINVOICE_CREATEDСANCELLEDСоздание счётаПокупка подтвержденаCONFIRMEDСчёт отменёнВозврат по счётуОтмена покупки

Статусная модель покупки подписок (SUBSCRIPTIONS)

img

Потребление (подтверждение) покупки

Продукты, требующие потребления (подтверждения)

Учитывайте тип покупки. Метод потребления (подтверждения) необходим, только если у вас потребляемый товар (CONSUMABLE), который можно купить много раз.

Чтобы такие товары начислились пользователям без ошибок, подтвердите потребление (подтверждение) продукта с помощью метода confirmPurchase. При начислении товара в вашем приложении используйте серверную валидацию платежей. Начисляйте товар только когда платёж (счёт) перейдет в финальный статус CONFIRMED. Начисление продуктов пользователям надо делать в callback addOnSuccessListener метода confirmPurchase.

Обратите внимание!

Статус PAID является промежуточным и означает, что средства пользователя захолдированы на карте и вам нужно подтвердить покупку.

Исключение составляют платежи через СБП или мобильное списание — см. пояснения ниже.

При оплате потребляемых (CONSUMABLE) товаров через СБП или мобильное списание используется одностадийный платёж, при этом модель счёта остаётся двухстадийной. Это значит, что при переходе счёта в статус PAID при оплате через СБП или мобильное списание деньги уже списаны со счёта покупателя, а с разработчика удержана комиссия. В этом случае при отмене покупки в состоянии PAID происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается. При этом для завершения покупки всё равно нужно выполнить метод подтверждения (потребления) — см. также таблицу ниже.

Платёжный методТип платежаПлатёж в статусе PAID
  • банковские карты;
  • Сбер ID;
  • SberPay;
  • T-Pay;
  • VK Pay.
Двухстадийный
  • Средства захолдированы на счёте покупателя.
  • Комиссия с разработчика не удержана.
  • Возможна отмена платежа.
  • СБП;
  • мобильное списание.
Одностадийный
  • Средства списаны со счёта покупателя.
  • Удержана комиссия с разработчика.
  • При отмене покупки в состоянии PAID происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается.

Вызов метода потребления (подтверждения)

Для потребления (подтверждения) покупки используйте метод ConfirmPurchase. Запрос на потребление (подтверждение) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдёт в статус CONSUMED.

Вызов метода ConfirmPurchase
long requestId = RuStoreBillingClient::Instance()->ConfirmPurchase(
purchaseId,
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
},
[]( long requestId, TSharedPtr<FURuStoreConfirmPurchaseResponse, ESPMode::ThreadSafe> response) {
// Process response
}
);
img
  • purchaseId — идентификатор покупки.

Обратный вызов (callback) Failure возвращает структуру FURuStoreError с информацией об ошибке в параметре Error. Структура ошибки FURuStoreError описана в разделе Обработка ошибок.

Отмена покупки

Для отмены покупки используйте метод DeletePurchase.

Вызов метода отмены покупки

Вызов метода DeletePurchase
long requestId = URuStoreBillingClient::Instance()->DeletePurchase(
purchaseId,
[]( long requestId, TSharedPtr<FURuStoreDeletePurchaseResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img
  • purchaseId — идентификатор покупки.
к сведению

Используйте этот метод, если у вас есть логика, завязанная на удалении покупки. Покупка отменяется автоматически через таймаут в 20 минут, либо при повторной покупке от того же клиента.

Обратный вызов (callback) Failure возвращает структуру FURuStoreError с информацией об ошибке в параметре Error. Структура ошибки FURuStoreError описана в разделе Обработка ошибок.

Обработка незавершённых платежей

Обработка незавершённых платежей производится разработчиком.

Чтобы подтвердить покупку типа CONSUMABLE и в статусе PAID вызовите метод потребления (подтверждения) покупки (см. Получение сведений о покупке).

В случае с отменой покупки при использовании методов обработки платежей учитывайте свой внутренний процесс. У некоторых разработчиков он предусматривает проверки перед потреблением (подтверждением) или отменой покупки. В этом случае запросите отдельно статус такой покупки.

подсказка

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

В случаях, когда метод получения списка покупок возвращает покупку со статусом INVOICE_CREATED вы можете использовать метод отмены покупки. Например, если не хотите видеть покупку с такими статусами в списке покупок. Делать это самим не обязательно, поскольку RuStore обрабатывает отмену таких покупок на своей стороне.

к сведению

Иногда после оплаты через приложение банка (СБП, SberPay, T-Pay и др.) и при последующем возврате обратно в приложение статус покупки остаётся INVOICE_CREATED, при этом статус платежа — неуспешная покупка. Это связано с временем обработки покупки на стороне банка. Поэтому разработчику необходимо правильно связать логику получения списка покупок с жизненным циклом экрана.

Альтернативное решение — отмена покупки в статусе INVOICE_CREATED только через взаимодействие пользователя с приложением. Например, вы можете вынести эту логику в отдельную кнопку.

Ведение журнала событий

Если вам необходимо логировать события библиотеки платежей, установите параметр enableLogs = true в структуре FURuStoreBillingClientConfig при вызове метода Init.

Вызов метода Init
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = true;

URuStoreBillingClient::Instance()->Init(config);
img

При этом будет задействован объект BillingClientLogger реализующий вывод сообщений в Logcat.

class BillingClientLogger(private val tag: String) : ExternalPaymentLogger {

override fun d(e: Throwable?, message: () -> String) {
Log.d(tag, message.invoke(), e)
}

override fun e(e: Throwable?, message: () -> String) {
Log.e(tag, message.invoke(), e)
}

override fun i(e: Throwable?, message: () -> String) {
Log.i(tag, message.invoke(), e)
}

override fun v(e: Throwable?, message: () -> String) {
Log.v(tag, message.invoke(), e)
}

override fun w(e: Throwable?, message: () -> String) {
Log.w(tag, message.invoke(), e)
}
}

Смена темы интерфейса

Для динамической смены темы необходимо использовать метод SetTheme.

Вызов метода SetTheme
EURuStoreTheme theme = EURuStoreTheme::DARK;
URuStoreBillingClient::Instance()->SetTheme(theme);
img

theme — тип темы из перечисления EURuStoreTheme.

Тип темы

UENUM(BlueprintType)
enum class EURuStoreTheme : uint8
{
DARK UMETA(DisplayName = "DARK"),
LIGHT UMETA(DisplayName = "LIGHT")
};
  • DARK — тёмная тема.
  • LIGHT — светлая тема.

Получить информацию об установленной теме можно используя метод GetTheme.

Вызов метода GetTheme
EURuStoreTheme theme = URuStoreBillingClient::Instance()->GetTheme();
img

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

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

  • RuStoreNotInstalledException — на устройстве пользователя не установлен RuStore;
  • RuStoreOutdatedException — версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;
  • RuStoreUserUnauthorizedException — пользователь не авторизован в RuStore;
  • RuStoreRequestLimitReached — с момента последнего отображения процесса прошло слишком мало времени;
  • RuStoreReviewExists — этот пользователь уже оценил ваше приложение;
  • RuStoreInvalidReviewInfo — проблемы с ReviewInfo;
  • RuStoreException — базовая ошибка RuStore, от которой наследуются остальные ошибки.

Структура ошибки

USTRUCT(BlueprintType)
struct RUSTORECORE_API FURuStoreRuStoreError
{
GENERATED_USTRUCT_BODY()
FURuStoreRuStoreError()
{
name = "" ;
description = "" ;
}

UPROPERTY(BlueprintReadOnly)
FString name;

UPROPERTY(BlueprintReadOnly)
FString description;
};
  • name – имя ошибки.
  • description – описание ошибки.

Автоматическая обработка ошибок

При вызове метода PurchaseProduct ошибки обрабатываются автоматически.

Если при инициализации SDK был передан параметр allowNativeErrorHandling == true, при возникновении ошибки, кроме вызова соответствующего обработчика Failure, пользователю будет показан диалог с ошибкой.

Изменить это поведение можно в любое время, используя метод SetAllowNativeErrorHandling().

Вызов метода SetAllowNativeErrorHandling
RuStoreBillingClient::Instance()->SetAllowNativeErrorHandling(false);
img
  • true — показывать диалог.
  • false — не показывать диалог.

Коды ошибок

Ниже представлено описание возможных ошибок в поле errorCode.

HTTP-кодКод ошибкиОписание
40040001Параметры запроса неверны — не заполнены обязательные параметры/неверный формат параметров.
40040003Приложение не найдено.
40040004Статус приложения inactive.
40040005Продукт не найден.
40040006Статус продукта inactive.
40040007Недопустимый тип продукта. Поддерживаемые типы: consumable, non-consumable, subscription.
40040008Покупка с таким order_id уже существует.
40040009У текущего клиента найдена покупка этого продукта со статусом invoice_created. Необходимо предложить клиенту оплатить/отменить покупку.
40040010Для типа продукта consumable. У текущего клиента найдена покупка этого продукта со статусом paid. Сначала требуется подтвердить потребление покупки на устройстве, а затем можно отправлять следующий запрос на покупку этого продукта.
40040011Для типа продукта non-consumable. У текущего клиента найдена покупка этого продукта со статусом pre_confirmed/confirmed. Такой продукт уже приобретён. Более одного раза продукт не продаётся.
40040012Для типа продукта subscription. У текущего клиента найдена покупка этого продукта со статусом pre_confirmed/confirmed. Такой продукт уже приобретён. Более одного раза продукт не продаётся.
40040013Для типа продукта subscription. При обращении в сервис подписок за списком продуктов GET/products (serviceId, user_id) данные не были получены.
40040014Обязательный атрибут(-ы) не пришел в запросе.
40040015Не удалось изменить статус при обновлении покупки (переход запрещён).
40040016При покупке подписки непотребляемого продукта указано значение quantity > 1.
40040017Продукт удалён, новые покупки не доступны.
40040018Нельзя потреблять продукт с типом тип продукта.
40140101Невалидный токен.
40140102Время жизни токена истекло.
40340301Доступ к запрашиваемому ресурсу запрещён (неавторизованно).
40340302Для текущего токена текущий вызов не авторизован (метод запрещён).
40340303Идентификатор приложения в запросе и токен не совпадают.
40340305Неверный тип токена.
40440401Не найдено.
40840801Истекло время ожидания уведомления, указанное в запросе.
50050***Внутренняя ошибка платежного сервиса.