7.0.0
RuStore позволяет интегрировать платежи в мобильное приложение.
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
Пример реализации
Ознакомьтесь с приложением-примером чтобы узнать, как правильно интегрировать SDK платежей.
Все операции с клиентом также доступны из Blueprints. Ниже представлен пример инициализации.
Условия работы платежей
- Приложение загружено в Консоль RuStore.
- Приложение прошло модерацию (публиковать приложение необязательно).
- Подпись тестируемой сборки (например,
debug
) приложения должна совпадать с подписью сборки приложения, которая была загружена в консоль и прошла модерацию ранее (например,release
).
- Пользователь и приложение не должны быть заблокированы в 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
описана в разделе Обработка ошибок.
Проверка установки приложения RuStore
Чтобы проверить установлен ли на устройстве пользователя RuStore необходимо вызвать метод IsRuStoreInstalled
.
bool bIsRuStoreInstalled = URuStoreBillingClient::Instance()->IsRuStoreInstalled();
-
true
– RuStore установлен. -
false
– RuStore не установлен.
Работа с SDK
Получение списка продуктов
Вы проверили, что платежи доступны и пользователи могут совершать покупки. Теперь можно получить список продуктов. Используйте метод GetProducts()
, чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
long requestId = URuStoreBillingClient::Instance()->GetProducts(
productIds,
[]( 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
описана в разделе Обработка ошибок.
Получение списка покупок
Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.
Тип/Статус | INVOICE_CREATED | CONFIRMED | PAID |
---|---|---|---|
CONSUMABLE | + | + | |
NON-CONSUMABLE | + | + | |
SUBSCRIPTION | + | + |
Метод возвращает незавершённые состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтверждённые покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.
Для получения списка покупок пользователя используйте метод GetPurchases()
.
long requestId = URuStoreBillingClient::Instance()->GetPurchases(
[]( long requestId, TSharedPtr<FURuStorePurchasesResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Уведомление обратного вызова (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
}
);
purchaseId
— идентификатор покупки
Уведомление обратного вызова (callback) Success
возвращает структуру FURuStorePurchase
в параметре Response
.
Уведомление обратного вызова (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке. Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.
Статусная модель (purchaseState
)
Статусная модель покупки потребляемых продуктов (CONSUMABLES
)
Статусная модель покупки непотребляемых продуктов (NON-CONSUMABLES
)
Статусная модель покупки подписок (SUBSCRIPTIONS
)
Потребление (подтверждение) покупки
Продукты, требующие потребления (подтверждения)
Учитывайте тип покупки. Метод потребления (подтверждения) необходим, только если у вас потребляемый товар (CONSUMABLE
), который можно купить много раз.
Чтобы такие товары начислились пользователям без ошибок, подтвердите потребление (подтверждение) продукта с помощью метода confirmPurchase
.
При начислении товара в вашем приложении используйте серверную валидацию платежей. Начисляйте товар только когда платёж (счёт) перейдет в финальный статус CONFIRMED
.
Начисление продуктов пользователям надо делать в callback addOnSuccessListener
метода confirmPurchase
.
Статус PAID
является промежуточным и означает, что средства пользователя захолдированы на карте и вам нужно подтвердить покупку.
Исключение составляют платежи через СБП или мобильное списание — см. пояснения ниже.
При оплате потребляемых (CONSUMABLE
) товаров через СБП или мобильное списание используется одностадийный платёж, при этом модель счёта остаётся двухстадийной. Это значит, что при переходе счёта в статус PAID
при оплате через СБП или мобильное списание деньги уже списаны со счёта покупателя, а с разработчика удержана комиссия. В этом случае при отмене покупки в состоянии PAID
происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается. При этом для завершения покупки всё равно нужно выполнить метод подтверждения (потребления) — см. также таблицу ниже.
Платёжный метод | Тип платежа | Платёж в статусе PAID |
---|---|---|
| Двухстадийный |
|
| Одностадийный |
|
Вызов метода потребления (подтверждения)
Для потребления (подтверждения) покупки используйте методConfirmPurchase
. Запрос на потребление (подтверждение) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдёт в статус CONSUMED
.
long requestId = RuStoreBillingClient::Instance()->ConfirmPurchase(
purchaseId,
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
},
[]( long requestId, TSharedPtr<FURuStoreConfirmPurchaseResponse, ESPMode::ThreadSafe> response) {
// Process response
}
);
purchaseId
— идентификатор покупки.
Обратный вызов (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке в параметре Error
. Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.
Отмена покупки
Для отмены покупки используйте метод 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
}
);
purchaseId
— идентификатор покупки.
Используйте этот метод, если у вас есть логика, завязанная на удалении покупки. Покупка отменяется автоматически через таймаут в 20 минут, либо при повторной покупке от того же клиента.
Обратный вызов (callback) Failure
возвращает структуру FURuStoreError
с информацией об ошибке в параметре Error
. Структура ошибки FURuStoreError
описана в разделе Обработка ошибок.
Обработка незавершённых платежей
Обработка незавершённых платежей производится разработчиком.
Чтобы подтвердить покупку типа CONSUMABLE
и в статусе PAID
вызовите метод потребления (подтверждения) покупки (см. Получение сведений о покупке).
В случае с отменой покупки при использовании методов обработки платежей учитывайте свой внутренний процесс. У некоторых разработчиков он предусматривает проверки перед потреблением (подтверждением) или отменой покупки. В эт ом случае запросите отдельно статус такой покупки.
Например, если пользователь оплатил товар, который вы по каким-то причинам не можете ему поставить, вызовите метод отмены покупки в статусе PAID
, чтобы отменить покупку.
В случаях, когда метод получения списка покупок возвращает покупку со статусом INVOICE_CREATED
вы можете использовать метод отмены покупки. Например, если не хотите видеть покупку с такими статусами в списке покупок. Делать это самим не обязательно, поскольку RuStore обрабатывает отмену таких покупок на своей стороне.
Иногда после оплаты через приложение банка (СБП, SberPay, T-Pay и др.) и при последующем возврате обратно в приложение статус покупки остаётся INVOICE_CREATED
, при этом статус платежа — неуспешная покупка. Это связано с временем обработки покупки на стороне банка. Поэтому разработчику необходимо правильно связать логику получения списка покупок с жизненным циклом экрана.
Альтернативное решение — отмена покупки в статусе INVOICE_CREATED
только через взаимодействие пользователя с приложением. Например, вы можете вынести эту логику в отдельную кнопку.
Ведение журнала событий
Если вам необходимо логировать события библиотеки платежей, установите параметр enableLogs = true
в структуре FURuStoreBillingClientConfig
при вызове метода Init
.
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = true;
URuStoreBillingClient::Instance()->Init(config);
При этом будет задействован объект 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
.
EURuStoreTheme theme = EURuStoreTheme::DARK;
URuStoreBillingClient::Instance()->SetTheme(theme);
theme
— тип темы из перечисления EURuStoreTheme
.
Тип темы
UENUM(BlueprintType)
enum class EURuStoreTheme : uint8
{
DARK UMETA(DisplayName = "DARK"),
LIGHT UMETA(DisplayName = "LIGHT")
};
DARK
— тёмная тема.LIGHT
— светлая тема.
Получить информацию об установленной теме можно используя метод GetTheme
.
EURuStoreTheme theme = URuStoreBillingClient::Instance()->GetTheme();
Обработка ошибок
Возможные ошибки
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()
.
RuStoreBillingClient::Instance()->SetAllowNativeErrorHandling(false);
true
— показывать диалог.false
— не показывать диалог.
Коды ошибок
Ниже представлено описание возможных ошибок в поле errorCode
.
HTTP-код | Код ошибки | Описание |
---|---|---|
400 | 40001 | Параметры запроса неверны — не заполнены обязательные параметры/неверный формат параметров. |
400 | 40003 | Приложение не найдено. |
400 | 40004 | Статус приложения inactive . |
400 | 40005 | Продукт не найден. |
400 | 40006 | Статус продукта inactive . |
400 | 40007 | Недопустимый тип продукта. Поддерживаемые типы: consumable , non-consumable , subscription . |
400 | 40008 | Покупка с таким order_id уже существует. |
400 | 40009 | У текущего клиента найдена покупка этого продукта со статусом invoice_created . Необходимо предложить клиенту оплатить/отменить покупку. |
400 | 40010 | Для типа продукта consumable . У текущего клиента найдена покупка этого продукта со статусом paid . Сначала требуется подтвердить потребление покупки на устройстве, а затем можно отправлять следующий запрос на покупку этого продукта. |
400 | 40011 | Для типа продукта non-consumable . У текущего клиента найдена покупка этого продукта со статусом pre_confirmed /confirmed . Такой продукт уже приобретён. Более одного раза продукт не продаётся. |
400 | 40012 | Для типа продукта subscription . У текущего клиента найдена покупка этого продукта со статусом pre_confirmed /confirmed . Такой продукт уже приобретён. Более одного раза продукт не продаётся. |
400 | 40013 | Для типа продукта subscription . При обращении в сервис подписок за списком продуктов GET/products (serviceId , user_id ) данные не были получены. |
400 | 40014 | Обязательный атрибут(-ы) не пришел в запросе. |
400 | 40015 | Не удалось изменить статус при обновлении покупки (переход запрещён). |
400 | 40016 | При покупке подписки непотребляемого продукта указано значение quantity > 1 . |
400 | 40017 | Продукт удалён, новые покупки не доступны. |
400 | 40018 | Нельзя потреблять продукт с типом тип продукта . |
401 | 40101 | Невалидный токен. |
401 | 40102 | Время жизни токена истекло. |
403 | 40301 | Доступ к запрашиваемому ресурсу запрещён (неавторизованно). |
403 | 40302 | Для текущего токена текущий вызов не авторизован (метод запрещён). |
403 | 40303 | Идентификатор приложения в запросе и токен не совпадают. |
403 | 40305 | Неверный тип токена. |
404 | 40401 | Не найдено. |
408 | 40801 | Истекло время ожидания уведомления, указанное в запросе. |
500 | 50*** | Внутренняя ошибка платежного сервиса. |