SDK Платежи in-app и подписки для Unity (версия 6.1.1)
RuStore позволяет интегрировать платежи в мобильное приложение.
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
Подключение в проект
- Установка через .unitypackage
- Установка через Package Manager
Для подключения скачайте файл RuStoreUnityBillingSDK-version.unitypackage
и импортируйте его в проект (Assets > Import Package > Custom Package). Зависимости подключаются автоматически с помощью External Dependency Manager (включен в .unitypackage
).
Если вы используете операционную систему macOS, измените настройки утилиты архивации. В настройках Archive Utility снимите флажок Keep expanding if possible. В противном случае архив проекта будет скачан некорректно.
Также вы можете склонировать код с помощью Git.
Для корректной обработки зависимостей SDK выполните следующие настройки.
-
Откройте настройки проекта: Edit → Project Settings → Player → Android Settings.
-
В pазделе Publishing Settings включите следующие настройки.
- Custom Main Manifest.
- Custom Main Gradle Template.
- Custom Gradle Properties Template.
-
В разделе Other Settings настройте:
- package name.
- Minimum API Level = 24.
- Target API Level = 34.
-
Откройте настройки External Dependency Manager: Assets → External Dependency Manager → Android Resolver → Settings, включите следующие настройки.
- Use Jetifier.
- Patch mainTemplate.gradle.
- Patch gradleTemplate.properties.
-
Обновите зависимости проекта: Assets → External Dependency Manager → Android Resolver → Force Resolve.
Минификация приложения (ProGuard/R8) в данный момент не поддерживается, необходимо её отключить в настройках проекта (File > Build Settings > Player Settings > Publishing Settings > Minify).
Обновление
Версии плагина 6.1.0 и выше содержат измененную структуру директорий. Измененная структура позволяет использовать преимущества раздельных сборок частей проекта Assembly definitions.
Перед установкой обновления выполните удаление следующих папок.
- Assets > RuStoreSDK > BillingClient > Editor.
- Assets > RuStoreSDK > Common > Editor.

После удаления импортируйте новый .unitypackage
в проект как при обычной установке (Assets > Import Package > Custom Package).
Для подключения скачайте со страницы upm_tgz пакеты:
ru.rustore.core-x.y.z.tgz
ru.rustore.billing-x.y.z.tgz
Импортируйте пакеты в проект через Package Manager (Window > Package Manager > + > Add package from tarball...).
Зависимости подключаются автоматически с помощью External Dependency Manager:
- Откройте окно менеджера пакетов (Window > Package Manager > + > Add package from git URL...).
- Используйте ссылку https://github.com/googlesamples/unity-jar-resolver.git?path=/upm для подключения пакета.
- Для устранения ошибки
Google.IOSResolver.dll will not be loaded
установите модуль сборки iOS для вашей версии Unity (UnityHub > Installs > Ваша версия Unity > Add modules > iOS Build Support).
Assembly 'Packages/com.google.external-dependency-manager/ExternalDependencyManager/Editor/1.2.182/Google.IOSResolver.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.
Если вы используете операционную систему macOS, измените настройки утилиты архивации. В настройках Archive Utility снимите флажок Keep expanding if possible. В противном случае архив проекта будет скачан некорректно.
Для корректной обработки зависимостей SDK выполните следующие настройки.
-
Откройте настройки проекта: Edit → Project Settings → Player → Android Settings.
-
В pазделе Publishing Settings включите следующие настройки.
- Custom Main Manifest.
- Custom Main Gradle Template.
- Custom Gradle Properties Template.
-
В разделе Other Settings настройте:
- package name.
- Minimum API Level = 24.
- Target API Level = 34.
-
Откройте настройки External Dependency Manager: Assets → External Dependency Manager → Android Resolver → Settings, включите следующие настройки.
- Use Jetifier.
- Patch mainTemplate.gradle.
- Patch gradleTemplate.properties.
-
Обновите зависимости проекта: Assets → External Dependency Manager → Android Resolver → Force Resolve.
Инициализация SDK
Перед вызовом методов библиотеки необходимо выполнить её инициализацию.
Выберите в меню редактора пункт Window > RuStoreSDK > Settings > Billing Client.
RuStoreBillingClient.Instance.Init();
Если требуется инициализация с другими настройками, есть возможность передать их непосредственно из кода.
var config = new RuStoreBillingClientConfig() {
consoleApplicationId = "123456" ,
deeplinkPrefix = "yourappscheme" ,
allowNativeErrorHandling = true,
enableLogs = true
};
RuStoreBillingClient.Instance.Init(config);
-
consoleApplicationId
— идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/
и/versions
. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versions
ID приложения —123456
.
-
deeplinkPrefix
— URL-адрес для использования deeplink. В качестве названия может быть использовано любое уникальное имя (пример:yourappscheme
). -
allowNativeErrorHandling
— разрешить обработку ошибок в нативном SDK (см. подробнее в разделе Обработка ошибок). -
enableLogs
— включить ведение журнала событий.
deeplinkPrefix
, долж на совпадать со схемой, указанной в AndroidManifest.xml
(подробнее см. Обработка deeplink).Если вам нужно проверить факт инициализации библиотеки, используйте свойство RuStoreBillingClient.Instance.isInitialized
— его значение true
, если библиотека инициализирована, и false
, если Init
еще не был вызван.
var isInitialized = RuStoreBillingClient.Instance.IsInitialized;
Обработка deeplink
Использование deeplink в RuStore SDK позволяет эффективно взаимодействовать со сторонними приложениями, например, при проведении платежей через банковские приложения (СБП, SberPay, T-Pay и др.). Это позволяет перевести пользователя на экран оплаты, а после завершения транзакции — вернуть в ваше приложение.
Для настройки работы с deeplink в вашем приложении и RuStore SDK, укажите deeplinkScheme
внутри вашего AndroidManifest
файла и переопределите метод onNewIntent
вашего Activity
.
<activity
android:name="ru.rustore.unitysdk.RuStoreUnityActivity" android:theme ="@style/UnityThemeSelector" 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"/>
<data android:scheme="yourappscheme"/>
</intent-filter>
</activity>
Вместо yourappscheme
из примера выше укажите название своей схемы. Например, ru.package.name.rustore.scheme
.
Далее расширьте класс UnityPlayerActivity
и добавьте обработку входящего intent
в onNewIntent
.
package ru.rustore.unitysdk;
import android.os.Bundle;
import android.content.Intent;
import ru.rustore.unitysdk.billingclient.RuStoreUnityBillingClient;
import com.unity3d.player.UnityPlayerActivity;
public class RuStoreUnityActivity extends UnityPlayerActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreUnityBillingClient.onNewIntent(getIntent());
}
}
@Override protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
RuStoreUnityBillingClient.onNewIntent(intent);
}
}
Разместите Java-файл с кодом расширения UnityPlayerActivity
в папке проекта Assets
. Если у вас уже есть своё расширение UnityPlayerActivity
, перенесите в него код функций onCreate
и onNewIntent
.
Методы SDK
Покупка продукта
Для вызова п окупки продукта используйте метод PurchaseProduct
.
RuStoreBillingClient.Instance.PurchaseProduct(
productId: productId,
quantity: 1,
developerPayload: "your payload",
onFailure: (error) => {
// process error
},
onSuccess: (result) => {
// process result
}
);
productId: String
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).orderId: String
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.quantity: Int
— количество продукта (необязательный параметр — если не указывать, будет использоваться значение1
).developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.
Структура результата покупки
public class PaymentResult {
}
public class PaymentSuccess : PaymentResult {
public string orderId;
public string purchaseId;
public string productId;
public string invoiceId;
public string subscriptionToken;
public bool sandbox;
}
public class PaymentCancelled : PaymentResult {
public string purchaseId;
public bool sandbox;
}
public class PaymentFailure : PaymentResult {
public string purchaseId;
public string invoiceId;
public string orderId;
public int quantity;
public string productId;
public int errorCode;
public bool sandbox;
}
public class InvalidPaymentState : PaymentResult {
}
Параметр sandbox
определяет, является ли платёж тестовым. Значения могут быть true
или false
,
где true
обозначает тестовый платёж, а false
– реальный.
PaymentSuccess
— результат успешного завершения покупки цифрового товара.PaymentFailure
— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.PaymentCancelled
— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.InvalidPaymentState
— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.
Подтверждение (потребление) покупки
Продукты, требующие подтверждения (потребления)
Учитывайте тип покупки. Метод подтверждения (потребления) необходим, только если у вас потребляемый товар (CONSUMABLE
), которы й можно купить много раз.
Чтобы такие товары начислились пользователям без ошибок, подтвердите подтверждение (потребление) продукта с помощью метода confirmPurchase
.
При начислении товара в вашем приложении используйте серверную валидацию платежей. Начисляйте товар только когда платёж (счёт) перейдет в финальный статус CONFIRMED
.
Начисление продуктов пользователям надо делать в callback addOnSuccessListener
метода confirmPurchase
.
Статус PAID
является промежуточным и означает, что средства пользователя захолдированы на карте и вам нужно подтвердить покупку.
Исключение — платежи через СБП или со счёта телефона: при этих способах оплаты используется одностадийный платёж, но модель счёта остаётся двухстадийной. Подробнее см. пояснения ниже.
При оплате потребляемых (CONSUMABLE
) товаров через СБП или со счета телефона используется одностадийный платёж, при этом модель счёта остаётся двухстадийной. Это значит, что при переходе счёта в статус PAID
при оплате через СБП или со счета мобильного телефона деньги уже списаны со счёта покупателя, а с разработчика удержана комиссия. В этом случае при отмене покупки в состоянии PAID
происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается. При этом для завершения покупки всё равно нужно выполнить метод подтверждения (потребления) — см. также таблицу ниже.
Платёжный метод | Тип платежа | Платёж в статусе PAID |
---|---|---|
| Двухстадийный |
|
| Одностадийный |
|
Вызов метода подтверждения (потребления)
Для подтверждения (потребления) покупки используйте методconfirmPurchase
. Запрос на подтверждение (потребление) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдёт в статус CONSUMED
.
RuStoreBillingClient.Instance.ConfirmPurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
purchaseId
— идентификатор покупки.
Отмена покупки
Для отмены покупки используйте метод DeletePurchase
.
RuStoreBillingClient.Instance.DeletePurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
purchaseId
— идентификатор покупки.
Используйте метод отмены покупки с осторожностью и только в исключительных случаях, только если покупка осталась в статусе PAID
, а вы не можете выдать товар пользователю. В остальных случаях не рекомендуется вручную отменять покупки, так как RuStore автоматически обрабатывает незавершённые покупки (например, таймаут в 20 минут или повторная покупка от того же клиента).
При оплате покупки через СБП или со счета мобильного телефона отмена покупки в статусе PAID
не отменяет холдирование, а приводит к возврату средств (refund). При этом с разработчика удерживается комиссия, которая не возвращается.
Получение сведений о покупке
Для получения информации о покупке, используйте методgetPurchaseInfo
.
RuStoreBillingClient.Instance.GetPurchaseInfo(
purchaseId: "purchaseId",
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);
Метод возвращает объект Purchase
с информацией о покупке.
Структура покупки
public class Purchase {
public enum PurchaseState
{
CREATED,
INVOICE_CREATED,
CONFIRMED,
PAID,
CANCELLED,
CONSUMED,
CLOSED
}
public string purchaseId;
public string productId;
public Product.ProductType productType;
public string invoiceId;
public string language;
public DateTime purchaseTime;
public string orderId;
public string amountLabel;
public int amount;
public string currency;
public int quantity;
public PurchaseState purchaseState;
public string developerPayload;
public string subscriptionToken;
}
purchaseId
— идентификатор покупки.productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).invoiceId
— идентификатор счёта.language
— язык, указанный с помощью BCP 47 кодирования.purchaseTime
— время покупки.orderId
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.amountLable
— отформатированная цена покупки, включая валютный знак.amount
— цена в минимальных единицах валюты.currency
— код валюты ISO 4217.quantity
— количество продукта (необязательный параметр — если не указывать, будет использоваться значение1
).purchaseState
— состояние покупки:developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.subscriptionToken
— токен для валидации покупки на сервере.
Статусная модель (purchaseState
)
Статусная модель покупки потребляемых продуктов (CONSUMABLES
)

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

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

Получение списка покупок
Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.
Тип/Статус | INVOICE_CREATED | CONFIRMED | PAID | PAUSED |
---|---|---|---|---|
CONSUMABLE | + | + | ||
NON-CONSUMABLE | + | + | ||
SUBSCRIPTION | + | + | + |
Метод возвращает незавершённые состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтверждённые покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.
Для получения списка покупок пользователя используйте метод GetPurchases
.
RuStoreBillingClient.Instance.GetPurchases(
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);
Метод возвращает List<Purchase> response
— список покупок.
Структура покупки
public class Purchase {
public enum PurchaseState
{
CREATED,
INVOICE_CREATED,
CONFIRMED,
PAID,
CANCELLED,
CONSUMED,
CLOSED,
PAUSED,
TERMINATED
}
public string purchaseId;
public string productId;
public Product.ProductType productType;
public string invoiceId;
public string language;
public DateTime purchaseTime;
public string orderId;
public string amountLabel;
public int amount;
public string currency;
public int quantity;
public PurchaseState purchaseState;
public string developerPayload;
public string subscriptionToken;
}
purchaseId
— идентификатор покупки.productId
— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).invoiceId
— идентификатор счёта.language
— язык, указанный с помощью BCP 47 кодирования.purchaseTime
— время покупки.orderId
— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.amountLable
— отформатированная цена покупки, включая валютный знак.amount
— цена в минимальных единицах валюты.currency
— код валюты ISO 4217.quantity
— количество продукта (необязательный параметр — если не указывать, будет использоваться значение1
).purchaseState
— состояние покупки:developerPayload
— строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.subscriptionToken
— токен для валидации покупки на сервере.
Получение списка продуктов
Вы проверили, что платежи доступны и пользователи могут совершать покупки. Теперь можно получить список продуктов. Используйте метод GetProducts
, чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
RuStoreBillingClient.Instance.GetProducts(productsId,
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);
string[] productIds
— список идентификаторов продуктов. В нём не должно быть более 100 позиций.
Чтобы указать id
продуктов, которые нужны для работы метода, выполните следующие действия.
- Откройте RuStore Консоль.
- Перейдите на вкладку Приложения.
- Выберите нужное приложение.
- В левом боковом меню выберите раздел Монетизация.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров. Это и есть
id
продуктов.
Метод возвращает список продуктов List<Product>
.
Структура продукта
public class Product {
public enum ProductStatus {
ACTIVE,
INACTIVE
}
public enum ProductType {
NON_CONSUMABLE,
CONSUMABLE,
SUBSCRIPTION
}
public string productId;
public ProductType productType;
public ProductStatus productStatus;
public string priceLabel;
public int price;
public string currency;
public string language;
public string title;
public string description;
public string imageUrl;
public string promoImageUrl;
public ProductSubscription 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
.
Структура подписки
public class ProductSubscription {
public SubscriptionPeriod subscriptionPeriod;
public SubscriptionPeriod freeTrialPeriod;
public SubscriptionPeriod gracePeriod;
public string introductoryPrice;
public string introductoryPriceAmount;
public SubscriptionPeriod introductoryPricePeriod;
}
subscriptionPeriod
— период подписки.freeTrialPeriod
— пробный период подписки.gracePeriod
— льготный период подписки.introductoryPrice
— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language
.introductoryPriceAmount
— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod
— расчётный период вступительной цены.
Структура периода подписки
public class SubscriptionPeriod {
public int years;
public int months;
public int days;
}
years
— количество лет.months
— количество месяцев.days
— количество дней.
Проверка доступности работы с платежами
Метод устарел и не рекомендуется к использованию.
Для проверки доступности платежей используйте метод
CheckPurchasesAvailability
.
FeatureAvailabilityResult.isAvailable == true
.
В противном случае возвращается FeatureAvailabilityResult.isAvailable == false
, где FeatureAvailabilityResult.cause
— это ошибка о невыполненном условии.
Все возможные ошибки RuStoreException
описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure
. (См. Task API).
RuStoreBillingClient.Instance.CheckPurchasesAvailability(
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
if (response.isAvailable) {
// Process purchases available
} else {
// Process purchases unavailable
}
}
);
Обработка незавершённых платежей производится разработчиком.
Чтобы подтвердить покупку продукта типа CONSUMABLE
и в статусе PAID
(см. Получение сведений о покупке), вызовите метод подтверждения (потребления) покупки.
Без подтверждения RuStore не перечислит средства на счёт разработчика. Это действие необходимо для финализации процесса покупки и начисления товара пользователю.
Если вы по каким-либо причинам не можете предоставить оплаченный товар, рекомендуется отменить покупку самостоятельно. Если вы этого не сделаете, RuStore автоматически отменит покупку по истечении определённого времени.
Используйте метод отмены покупки аккуратно и только в крайних случаях, например, когда пользователь оплатил товар (статус покупки PAID
), но вы не можете его предоставить. В остальных случаях вручную отменять покупки не рекомендуется — RuStore самостоятельно обрабатывает покупки в статусах INVOICE_CREATED
и других промежуточных статусах.
Особое внимание при оплате через СБП или со счета мобильного телефона:
- При отмене покупки в статусе
PAID
средства не разблокируются (reverse), а возвращаются пользователю (refund) поскольку указанные способы оплаты не поддерживают технологии двухстадийной оплаты. В этом случае с разработчика удерживается комиссия, которая не подлежит возврату. Поэтому перед отменой убедитесь, что это действительно необходимо.
Если вы используете собственную логику обработки платежей, рекомендуем всегда дополнительно проверять текущий статус покупки перед отменой.
Также вы можете подтверждать или отменять покупки через API RuStore:
Если пользователь оплатил товар, который вы по каким-то причинам не можете ему поставить, вызовите метод отмены покупки в статусе PAID
, чтобы отменить покупку.
Смена темы интерфейса
SDK поддерживает динамическую смены темы через интерфейс провайдера BillingClientThemeProvider
.
Получить текущую тему интерфейса можно с помощью метода GetTheme()
.
RuStoreBillingClient.Instance.GetTheme()
Изменить текущую тему можно использовав метод SetTheme(BillingClientTheme theme)
.
RuStoreBillingClient.Instance.SetTheme(BillingClientTheme.Dark)
Доступные темы перечислены в BillingClientTheme
.
public enum BillingClientTheme {
Dark,
Light,
}
Обработка ошибок
Возможные ошибки
RuStoreNotInstalledException
— на устройстве пользователя не установлен RuStore;RuStoreOutdatedException
— версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;RuStoreUserUnauthorizedException
— пользователь не авторизован в RuStore;RuStoreRequestLimitReached
— с момента последнего отображения процесса прошло слишком мало времени;RuStoreReviewExists
— этот пользователь уже оценил ваше приложение;RuStoreInvalidReviewInfo
— проблемы сReviewInfo
;RuStoreException
— базовая ошибка RuStore, от которой наследуются остальные ошибки.
Возникающие ошибки передаются в обработчик методов SDK onFailure
.
Структура ошибки
public class RuStoreError {
public string name;
public string description;
}
name
– имя ошибки.description
– описание ошибки.
Автоматическая обработка ошибок
При вызове методаPurchaseProduct
ошибки обрабатываются автоматически.
Если при инициализации SDK был передан параметр allowNativeErrorHandling == true
, при возникновении ошибки, кроме вызова соответствующего обработчика Failure
, пользователю будет показан диалог с ошибкой.
public fun RuStoreException.resolveForBilling(context: Context)
Изменить это поведение после инициализации можно установкой свойства AllowNativeErrorHandling
.
RuStoreBillingClient.Instance.AllowNativeErrorHandling = false;