7.0.0 (Beta)
RuStore позволяет интегрировать платежи в мобильное приложение.
-
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
-
Если вы переходите на Pay SDK с billingClient SDK, ознакомьтесь с инструкцией по переходу. Подробности о Pay SDK можно узнать тут.
Пример реализации
Ознакомьтесь с приложением-при мером чтобы узнать, как правильно интегрировать SDK платежей.
Условия работы платежей
- Для приложения включена возможность покупок в RuStore Консоли.
- Приложение не должно быть заблокировано в RuStore.
- На устройстве пользователя установлена актуальная версия RuStore.
- Пользователь авторизован в RuStore.
- Пользователь не должен быть заблокирован в RuStore.
Подготовка к работе
- Скопируйте проекты плагина и приложения-примера из официального репозитория 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 — не ниже 31.
Настройка Unreal Engine
Для версий Unreal Engine младше 5.4 должно быть выполнено обновление gradle и gradle-wrapper.
- Перейдите в корневую директорию установки Unreal Engine (например:
C:\Program Files\Epic Games\UE_4.26
). - В файле
\Engine\Build\Android\Java\gradle\build.gradle
задайте версию пакетаcom.android.tools.build:gradle
не ниже4.2.2
. - В файле
\Engine\Build\Android\Java\gradle\gradle\wrapper\gradle-wrapper.properties
задайте версию пакетаgradle
не ниже7.5-all
.
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
apply from: 'buildscriptAdditions.gradle', to: buildscript
}
apply from: 'baseBuildAdditions.gradle'
allprojects {
repositories {
google()
mavenCentral()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
Инициализация
Перед вызовом методов библиотеки необходимо выполнить её инициализацию. Сама инициализация происходит автоматически, но для работы SDK в вашем файле необходимо прописать
. Знач ение необходимо указать в строковых ресурсах.
Сделать это можно следующим образом.
URuStorePayClient::Instance()->Init();
Для работы SDK в вашем AndroidManifest.xml
плагин RuStorePay через файл RuStorePay_UPL_Android.xml
добавит в манифест приложения данные console_app_id_key
и internal_config_key
. Оба значения располагаются внутри тэга <application>
.
<application>
...
<meta-data android:name="console_app_id_key" android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data android:name="internal_config_key" android:value="unreal" />
</application>
internal_config_key
– всегда имеет значениеunreal
.-
console_app_id_key
— идентификатор приложения из консоли RuStore.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/
и/versions
. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versions
ID приложения —123456
.
Package Name приложения, указанный в Edit ➝ Project Settings... ➝ Player ➝ Android ➝ Other Settings ➝ Package Name, должен совпадать с Package Name APK-файла, который вы публиковали в системе RuStore Консоль.
Подпись keystore
должна совпадать с подписью, которой было подписано приложение, опубликованное в системе RuStore Консоль. Убедитесь, что используемый buildType
(пр. debug
) использует такую же подпись, что и опубликованное приложение (пр. release
).
Значение console_app_id_key
должно быть задано в файле ресурсов, например: rustore_pay_values.xml
.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="rustore_PayClientSettings_consoleApplicationId">198332</string>
</resources>
Файл ресурсов может быть включен в проект через UPL-файл вашего проекта, в следующем примере копирование файла rustore_pay_values.xml
будет выполняться из директории Source/YOUUR_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>
Не задавайте значения console_app_id_key
и internal_config_key
напрямую в манифесте. Строки должны располагаться в файле ресурсов.
Деинициализация
Вызов метода Init
для URuStorePayClient
привязывает объекты к корню сцены. Если дальнейшая работа с объектами больше не планируется, для освобождения памяти необходимо выполнить метод Dispose
. Вызов Dispose
отвяжет объект от корня и безопасно завершит все отправленные запросы.
bool isInitialized = URuStorePayClient::Instance()->Dispose();
Проверка инициализации
Если вам нужно проверить факт инициализации библиотеки, используйте метод GetIsInitialized
. Метод вернет true
, если библиотека инициализирована, и false
, если Init
еще не был вызван.
bool isInitialized = URuStorePayClient::Instance()->GetIsIninialized();
Работа с SDK
Проверка доступности работы с платежами
Для проверки доступности платежей, вызовите метод GetPurchaseAvailability
. При его вызове проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в 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
}
);
Проверка установки приложения RuStore
Чтобы проверить установлен ли на устройстве пользователя RuStore необходимо вызвать метод IsRuStoreInstalled
.
bool bIsRuStoreInstalled = URuStorePayClient::Instance()->IsRuStoreInstalled();
-
true
– RuStore установлен. -
false
– RuStore не установлен.
Получение списка продуктов
Для получения продуктов, добавленных в ваше приложение через 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-CONSUMABE
(потребляемый/непотребляемый).amountLabel
— отформатированная цена покупки, включая валютный знак.price
— цена в минимальных единицах (в копейках).currency
— код валюты ISO 4217.title
— название продукта на языкеlanguage
.description
— описание на языкеlanguage
.imageUrl
— ссылка на картинку.
Покупка продукта
Одностадийна оплата (без холдирования средств)
Для вызова покупки продукта используйте методPurchaseOneStep
.
FURuStorePayProductPurchaseParams productPurchaseParams;
...
long requestId = URuStorePayClient::Instance()->PurchaseOneStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
auto type = response->GetTypeName();
if (type.Equals("FURuStorePaySuccessProductPurchaseResult"))
{
auto success = *StaticCastSharedPtr<FURuStorePaySuccessProductPurchaseResult>(response);
// Process success
}
else
if (type.Equals("FURuStorePayCancelledProductPurchaseResult"))
{
auto cancelled = *StaticCastSharedPtr<FURuStorePayCancelledProductPurchaseResult>(response);
// Process cancelled
}
else
if (type.Equals("FURuStorePayFailureProductPurchaseResult"))
{
auto failure = *StaticCastSharedPtr<FURuStorePayFailureProductPurchaseResult>(response);
// Process failure
}
else
{
// Process invalid state
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).quantity
— количество продукта (необязательный параметр — если не указывать, будет подставлено значение1
).orderId
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки. Максимальная длина 250 символов.
Двустадийна оплата (с холдированием средств)
FURuStorePayProductPurchaseParams productPurchaseParams;
...
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);
// Process success
}
else
if (type.Equals("FURuStorePayCancelledProductPurchaseResult"))
{
auto cancelled = *StaticCastSharedPtr<FURuStorePayCancelledProductPurchaseResult>(response);
// Process cancelled
}
else
if (type.Equals("FURuStorePayFailureProductPurchaseResult"))
{
auto failure = *StaticCastSharedPtr<FURuStorePayFailureProductPurchaseResult>(response);
// Process failure
}
else
{
// Process invalid state
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
Структура параметров покупки:
USTRUCT(BlueprintType)
struct FURuStorePayProductPurchaseParams
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity; // nullable
FURuStorePayProductPurchaseParams()
{
productId = NewObject<URuStorePayProductId>();
developerPayload = nullptr;
orderId = nullptr;
quantity = nullptr;
}
};
productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки (опционально).orderId
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов (опционально).quantity
— количество продукта (необязательный параметр — если не указывать, будет подставлено значение1
) (опционально).
Структура результата покупки:
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()
virtual ~FURuStorePayProductPurchaseResult() {}
virtual FString GetTypeName() { return "FURuStorePayProductPurchaseResult"; }
};
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePaySuccessProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;
UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken; // nullable
virtual FString GetTypeName() override { return "FURuStorePaySuccessProductPurchaseResult"; }
FURuStorePaySuccessProductPurchaseResult()
{
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
orderId = nullptr;
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
subscriptionToken = nullptr;
}
};
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayCancelledProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId; // nullable
virtual FString GetTypeName() override { return "FURuStorePayCancelledProductPurchaseResult"; }
FURuStorePayCancelledProductPurchaseResult()
{
purchaseId = nullptr;
}
};
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayFailureProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
FURuStoreError cause;
UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;
UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId;
UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;
UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;
UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;
UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken;
virtual FString GetTypeName() override { return "FURuStorePayFailureProductPurchaseResult"; }
FURuStorePayFailureProductPurchaseResult()
{
invoiceId = nullptr;
orderId = nullptr;
productId = nullptr;
purchaseId = nullptr;
quantity = nullptr;
subscriptionToken = nullptr;
}
};
FURuStorePaySuccessProductPurchaseResult
— результат успешного завершения покупки цифрового товара.FURuStorePayCancelProductPurchaseResult
— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.FURuStorePayFailureProductPurchaseResult
— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.