SDK Платежи in-app для Flutter (версия 10.0.0)
RuStore позволяет интегрировать платежи в мобильное приложение.
-
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
-
Если вы переходите на Pay SDK с billingClient SDK, ознакомьтесь с инструкцией по переходу. Подробности о Pay SDK можно узнать тут.
Подготовка к работе
Для подключения пакета платежей к проекту выполните следующую команду.
flutter pub add flutter_rustore_pay
Обработка deeplink
Обработка deeplink в RuStore SDK позволяет эффективно взаимодействовать со сторонними приложениями, при проведении платежей через банковские приложения (СБП, SberPay, T-Pay и др.). Это позволяет перевести пользователя на экран оплаты, а после завершения транзакции — вернуть в ваше приложение.
Для настройки работы с deeplink в вашем приложении и Pay SDK, укажите deeplinkScheme с помощью sdk_pay_scheme_value в AndroidManifest.xml файле.
При использовании deeplinks указание схемы является обязательным. При попытке платежа без указания схемы будет возникать ошибка.
Указание deeplinkScheme:
<activity
android:name=".sample.MainActivity">
<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="@string/SDK_PAY_SCHEME" /> />
</intent-filter>
<meta-data
android:name="sdk_pay_scheme_value"
android:value="@string/SDK_PAY_SCHEME" />
</activity>
Не забудьте указать строку с вашей SDK_PAY_SCHEME в файле strings.xml.
Для восстановления состояния вашего приложения при возврате с deeplink добавьте в
AndroidManifest.xml атрибут android:launchMode="singleTop".
Указание launchMode:
<activity
android:name=".YourPayActivity"
android:launchMode="singleTop
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
Инициализация SDK
Перед вызовом методов библиотеки необходимо выполнить её инициализацию. Сама инициализация происходит автоматически, но для работы SDK в вашем файле AndroidManifest.xml необходимо прописать console_app_id_value.
<meta-data
android:name="console_app_id_value"
android:value="@string/CONSOLE_APPLICATION_ID" />
В strings.xml замените строку с вашим app_id.
<string name="CONSOLE_APPLICATION_ID">your_app_id</string>
CONSOLE_APPLICATION_ID — идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/и/versions. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versionsID приложения —123456.

ApplicationId, указанный вbuild.gradle, должен совпадать сapplicationIdAPK-файла, который вы публиковали в RuStore Консоль.-
Подпись
keystoreдолжна совпадать с подписью, которой было подписано приложение, опубликованное в RuStore Консоль. Убедитесь, что используемыйbuildType(пр.debug) использует такую же подпись, что и опубликованное приложение (пр.release).
В целях безопасности, SDK устанавливает android:usesCleartextTraffic="false" по умолчанию, чтобы предотвратить передачу данных по незащищённому HTTP и защитить от атак типа "Man-in-the-Middle". Если ваше приложение требует использования HTTP, вы можете изменить этот атрибут на true, но делайте это на свой страх и риск, так как это увеличивает шанс перехвата и подмены данных. Мы рекомендуем разрешать незащищённый трафик только в исключительных случаях и для доверенных доменов, предпочитая HTTPS для всех сетевых взаимодействий.
Методы SDK
Доступные публичные интеракторы:
-
PurchaseInteractor- интерактор, который позволяет работать с платежами и имеет несколько публичных методов.getPurchase(purchaseId: PurchaseId): Task<Purchase>- позволяет получить информацию о покупке по её ID.getPurchases(productType: ProductType? = null, purchaseStatus: PurchaseStatus? = null): Task<List<Purchase>>— позволяет получить покупки пользователя. Данный метод поддерживает опциональную фильтрацию по типу товаров (потребляемые, непотребляемые товары или подписки), а также по статусу покупки (поддерживаются статусыPAID,CONFIRMEDACTIVEиPAUSED). По умолчанию фильтры отключены, и вернутся все покупки пользователя (независимо от типа товара) в статусахPAID,CONFIRMEDACTIVEиPAUSED.getPurchaseAvailability(): Task<PurchaseAvailabilityResult>- возвращает результат проверки доступности работы с платежами.purchase(params: ProductPurchaseParams, preferredPurchaseType: PreferredPurchaseType = PreferredPurchaseType.ONE_STEP): Task<ProductPurchaseResult>- позволяет совершить покупку продукта с указанием желаемого типа оплаты - одностадийной (ONE_STEP) или двухстадийной (TWO_STEP). Для данного метода оплаты на платёжной шторке доступны все способы оплаты. Если параметр не задан, по умолчанию запускается с оплатой в одну стадию.
Важно!Если указан тип оплаты
TWO_STEP, будет произведена попытка запустить двухстадийную оплату, но итоговый результат напрямую будет зависеть от того, какой способ оплаты (карта, СБП и др.) будет выбран пользователем.Обратите внимание, что тип оплаты
TWO_STEPнедоступен:-
При выборе способа оплаты СБП.
-
При покупке подписок.
Двухстадийная оплата доступна только для определенного набора способов оплаты (на текущий момент — только для карт и SberPay). Если выбран способ оплаты, который не поддерживает холдирование, то покупка будет запущена по сценарию с одной стадией.
purchaseTwoStep(params: ProductPurchaseParams): Task<ProductPurchaseResult>- запускает сценарий гарантированной двухстадийной покупки товара. При использовании данного метода пользователю на платёжной шторке доступен ограниченный набор способов оплаты - только те, которые поддерживают двухстадийную оплату. В процессе платежа сначала осуществляется холдирование денежных средств покупателя, которые списываются только после подтверждения покупки методомconfirmTwoStepPurchase.confirmTwoStepPurchase(purchaseId: PurchaseId, developerPayload: DeveloperPayload? = null)- подтверждение покупки, совершенной по двухстадийной оплате.cancelTwoStepPurchase(purchaseId: PurchaseId)- отмена покупки, совершённой по двухстадийной оплате.
-
ProductInteractor- интерактор, который позволяет работать с продуктами:getProducts(productsId: List<ProductId>): Task<List<Product>>- позволяет получить информацию по активным продуктам, опубликованным в RuStore консоль.
ВажноДанный метод возвращает не более 1000 продуктов и работает без авторизации и наличия установленного RuStore на устройстве пользователя.
-
UserInteractor- интерактор, который позволяет получить статус авторизации пользователяUserAuthorizationStatus. У данной модели может быть 2 состояния:Authorized- пользователь авторизован в RuStoreUnauthorized- пользователь неавторизован в RuStore.
-
IntentInteractor- интерактор, который позволяет обрабатывать intent-ы:proceedIntent(intent: Intent?)- метод для обработки deeplinks, использующихся для оплаты в приложениях банков. Вызов данного мето да необходим для корректного отображения шторки оплаты при возвращении в приложение из приложения банка.
-
блок
RuStoreUtils- набор открытых методов, таких как:isRuStoreInstalled- проверки наличия приложения RuStore на устройстве пользователя.openRuStoreDownloadInstruction- открывает веб-страницу для скачивания приложения RuStore.openRuStore- запускает приложение RuStore.openRuStoreAuthorization- запускает приложение RuStore для авторизации. После успешной авторизации пользователя приложение RuStore автоматически закроется.
Типы покупок
В SDK предусмотрен базовый интерфейс Purchase, который объединяет общие поля всех типов покупок.
На его основе созданы две реализации:
- ProductPurchase: для потребляемых и непотребляемых покупок.
- SubscriptionPurchase: для подписок.
Данное разделение позволяет каждому типу покупки иметь свои уникальные свойства и поведение.
abstract class Purchase {
String get purchaseId;
String get invoiceId;
String? get orderId;
PurchaseType get purchaseType;
PurchaseStatus get status;
String get description;
String? get purchaseTime; // ISO-8601
int get price;
String get amountLabel;
String get currency;
String? get developerPayload;
bool get sandbox;
}
Получение сведений о покупке
Для получения информации о покупке, используйте методgetPurchase.
RuStorePayClient.instance.purchaseInteractor.getPurchase("PURCHASE_ID").then((purchase) {
// Для получения информации о покупке определенного типа
if (purchase is ProductPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
} else if (purchase is SubscriptionPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
}
}).catchError((error) {
// Обработка ошибок
});
Метод возвращает информацию о конкретной покупке в любом статусе. Модель покупки указана в разделе типы покупок
Получение списка покупок
Для получения списка покупок пользователя используйте метод getPurchases.
RuStorePayClient.instance.purchaseInteractor.getPurchases().then((purchases) {
for (final purchase in purchases) {
// Для получения покупки определенного типа
if (purchase is ProductPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
} else if (purchase is SubscriptionPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
}
}
}).catchError((error) {
// Обработка ошибок
});
Данный метод позволяет фильтровать покупки по типу товаров и статусу покупки:
Типы товаров:
- Потребляемые товары -
ProductType.CONSUMABLE_PRODUCT - Непотребляемые товары -
ProductType.NON_CONSUMABLE_PRODUCT - Подписки -
ProductType.SUBSCRIPTION
Статусы покупок:
-
Для продуктов:
PAID: Успешное холдирование средств, покупка ожидает подтверждения со стороны разработчика.CONFIRMED: Покупка подтверждена, средства списаны.
-
Для подписок:
ACTIVE: Подписка активна.PAUSED: Подписка в Hold периоде (например, из-за недостатка средств на карте), продолжаются попытки списания в соответствии с настройками тарифа подписки.
По умолчанию фильтры выключены, если значения не заданы, метод вернёт все покупки пользователя в статусах PAID, CONFIRMED, ACTIVE и PAUSED, независимо от типа товара.
RuStorePayClient.instance.purchaseInteractor.getPurchases().then((purchases) {
// Для получения покупки определенного типа
for (final purchase in purchases) {
if (purchase is ProductPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
} else if (purchase is SubscriptionPurchase) {
print('Product ID: ${purchase.productId}, Status: ${purchase.status}');
}
}
}).catchError((error) {
// Обработка ошибок
});
Получение списка продуктов
Для получения продуктов, добавленных в ваше приложение через RuStore консоль, необходимо использовать метод getProducts.
RuStorePayClient.instance.productInteractor.getProducts(productIds).then((response) {
for (final product in response.products) {
print(product?.productId);
}
}, onError: (err) {
print("products err: $err");
}
);
productIds: List<ProductId> — список идентификаторов продуктов (задаются при создании продукта в консоли разработчика). Список продуктов имеет ограничение в размере 1000 элементов.
Где в RuStore Консоль отображаются идентификаторы продуктов?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Выберите Монетизация в меню слева.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров.

Метод возвращает список продуктов. Ниже представлена модель продукта.
class Product {
final String productId;
final ProductType type;
final String amountLabel;
final int? price; // nullable, если цена может отсутствовать
final String currency;
final String imageUrl;
final String title;
final String? description;
const Product({
required this.productId,
required this.type,
required this.amountLabel,
this.price,
required this.currency,
required this.imageUrl,
required this.title,
this.description,
});
}
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).type— тип продукта.CONSUMABLE/NON-CONSUMABLE(потребляемый/непотребляемый).amountLabel— отформатированная цена покупки, включая валютный знак.price— цена в минимальных единицах (в копейках).currency— код валюты ISO 4217.title— название продукта на языкеlanguage.description— описание на языкеlanguage.imageUrl— ссылка на картинку.
Примеры ответа
Product(
productId = ProductId("conProduct1"),
type = ProductType.CONSUMABLE_PRODUCT,
amountLabel = AmountLabel("100.00 руб."),
price = Price(10000),
currency = Currency("RUB"),
imageUrl = Url("https://your_image_consumable_product.png"),
title = Title("Название Потребляемого продукта"),
description = Description("Описание потребляемого продукта"),
)
Product(
productId = ProductId("nonConProduct1"),
type = ProductType.NON_CONSUMABLE_PRODUCT,
amountLabel = AmountLabel("200.00 руб."),
price = Price(20000),
currency = Currency("RUB"),
imageUrl = Url("https://your_image_non_consumable_product.png"),
title = Title("Название Непотребляемого продукта"),
description = Description("Описание Непотребляемого продукта"),
)
Product(
productId = ProductId("sub_1"),
type = ProductType.SUBSCRIPTION,
amountLabel = AmountLabel("300.00 руб."),
price = Price(30000),
currency = Currency("RUB"),
imageUrl = Url("https://your_image_subscription.png"),
title = Title("Название вашей подписки"),
description = Description("Описание вашей подписки"),
)
Определение наличия авторизации у пользователя
Для проверки статуса авторизации пользователя, вызовите метод getUserAuthorizationStatus у UserInteractor.
Результатом выполнения метода является класс UserAuthorizationStatus. Доступно 2 значения:
AUTHORIZED- пользователь авторизован в RuStoreUNAUTHORIZED- пользователь неавторизован в RuStore. Данное значение также вернется если у пользователя нет установленного RuStore на девайсе.
RuStorePayClient.instance.userInteractor.getUserAuthorizationStatus().then((value) {
if (value case Authorized _) {
// Process authorized
} else if (value case Unauthorized _) {
// Process unauthorized
}
});
Проверка доступности работы с платежами
Для проверки дос тупности платежей, вызовите метод getPurchaseAvailability. При его вызове проверяются следующие условия.
- Для приложения включена возможность покупок в RuStore Консоли.
- Пользователь и приложение не должны быть заблокированы в RuStore.
PurchaseAvailabilityResponse.Available.
В противном случае возвращается PurchaseAvailabilityResponse.Unavailable(val cause: Throwable), где cause — это ошибка о невыполненном условии.
RuStorePayClient.instance.purchaseInteractor.getPurchaseAvailability().then((value) {
if (value case Available _) {
// Process purchases available
} else if (value case Unavailable unavailable) {
// Process purchases unavailable
}
});
Модель разовой покупки ProductPurchase
Оплата с выбором типа покупки
Для вызова покупки продукта с выбором стадийности оплаты используйте метод purchase.
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
Future<void> purchaseProduct() async {
final params = ProductPurchaseParams(
productId: 'productId',
orderId: null,
quantity: null,
developerPayload: null,
appUserId: null,
appUserEmail: null,
);
try {
final result = await RuStorePayClient.instance.purchaseInteractor.purchase(
params.productId,
quantity: params.quantity ?? 1,
orderId: params.orderId,
developerPayload: params.developerPayload,
appUserId: params.appUserId,
appUserEmail: params.appUserEmail,
preferredPurchaseType: PreferredPurchaseType.oneStep,
);
// Логика обработки успешного результата покупки
} on RuStoreProductPurchaseException {
// Обработка ошибки покупки продукта
} on RuStorePurchaseCancelledException {
// Обработка отмены покупки продукта
} catch (_) {
// Обработка ошибки
}
}
preferredPurchaseType— желаемый тип покупки: одностадийная (ONE_STEP) или двухстадийная (TWO_STEP).
Данный метод по умолчанию запускается по одностадийному сценарию оплаты (preferredPurchaseType = PreferredPurchaseType.ONE_STEP), т.е. без холдирования средств.
Для двухстадийной оплаты нужно указать preferredPurchaseType = PreferredPurchaseType.TWO_STEP. Двухстадийная оплата (т.е. оплата с холдированием средств) для данного метода не гарантирована и напрямую зависит от того, какой способ оплаты (карта, СПБ и др.) выбрал пользователь.
При запуске данного метода (с предпочитаемым preferredPurchaseType = twoStep), до тех пор пока пользователь не выберет способ оплаты, стадийность покупки будет UNDEFINED. Учитывайте данное поведение при обработке результатов отмены (ProductPurchaseCancelled) или ошибки (ProductPurchaseException) покупки.
Двухстадийная оплата (с холдированием средств)
Для вызова покупки продукта по двухстадийному сценарию используйте метод purchaseTwoStep.
При вызове данного метода пользователю будет доступен ограниченный набор способов оплаты — только те, которые поддерживают двухстадийную оплату.
На данный момент покупка подписки (SubscriptionPurchase) может быть совершена только с использованием одностадийного платежа (PurchaseType.ONE_STEP).
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
Future<void> purchaseTwoStep() async {
final params = ProductPurchaseParams(
productId: 'productId',
orderId: null,
quantity: null,
developerPayload: null,
appUserId: null,
appUserEmail: null,
);
try {
final result = await RuStorePayClient.instance.purchaseInteractor.purchaseTwoStep(
params.productId,
quantity: params.quantity ?? 1,
orderId: params.orderId,
developerPayload: params.developerPayload,
appUserId: params.appUserId,
appUserEmail: params.appUserEmail,
);
// Логика обработки успешного результата покупки
} on RuStoreProductPurchaseException {
// Обработка ошибки покупки продукта
} on RuStorePurchaseCancelledException {
// Обработка отмены покупки продукта
} catch (_) {
// Обработка ошибки
}
}
Структура параметров покупки
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются.-
appUserId— внутренний ID пользователя в вашем приложении (опциональный параметр). Строка с максимальной длиной в 128 символов.tipНапример, данный параметр может использоваться для выявления случаев мошенничества в вашем приложении, что позволит повысить его безопасность.
appUserEmail— это необязательный параметр, позволяющий задать адрес электронной почты пользователя в вашем приложении. Если адрес электронной почты покупателя был указан при регистрации в приложении, его можно передать для автоматического заполнения поляemailпри отправке чека — как для платежей вне RuStore, так и для случаев, когда пользователь не авторизован в RuStore. Эт о избавляет пользователя от необходимости вручную вводить email, сокращает путь до покупки и способствует повышению конверсии.
Статусная модель покупки
Статусная модель одностадийного платежа.
Статусная модель двухстадийного платежа.
Модель подписки SubscriptionPurchase
class SubscriptionPurchase implements Purchase {
final String purchaseId;
final String invoiceId;
final String? orderId;
final PurchaseType purchaseType;
final SubscriptionPurchaseStatus status;
final String description;
final String? purchaseTime; // ISO-8601
final int price;
final String amountLabel;
final String currency;
final String? developerPayload;
final bool sandbox;
final String productId;
final String expirationDate; // ISO-8601
final bool gracePeriodEnabled;
const SubscriptionPurchase({
required this.purchaseId,
required this.invoiceId,
this.orderId,
required this.purchaseType,
required this.status,
required this.description,
this.purchaseTime,
required this.price,
required this.amountLabel,
required this.currency,
this.developerPayload,
required this.sandbox,
required this.productId,
required this.expirationDate,
required this.gracePeriodEnabled,
});
}
purchaseId— идентификатор покупки. Идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупке.invoiceId— идентификатор счёта. Идентификатор счёта. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей.orderId- уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).PurchaseType— тип покупки:ONE_STEP- одностадийная покупка;TWO_STEP- двухстадийная покупка;UNDEFINED- стадийность не определена.
status- состояние подписки:INVOICE_CREATED- создан счет на оплату, подписка ожидает оплаты.CANCELLED- счет на оплату подписки отменен.EXPIRED- срок действия оплаты счета истек.PROCESSING- первый платеж по подписке в обработке.REJECTED- первый платеж по подписке отклонен. Подписка не оформлена.ACTIVE- подписка активна.EXPIRED- срок действия подписки истек. - тоже самое, не подписки, а время на оплату счета первого для оформления подписки истекло, никакой подписки ещё не былоPAUSED- подписка приостановлена из-за проблем с оплатой.TERMINATED- закончились попытки списания по подписке (все были неуспешными). Подписка закрыта автоматически из-за проблем с оплатой.CLOSED- подписка была отменена пользователем или разработчиком. Истек срок оплаченного п ериода, подписка закрыта.
description- описание покупки.purchaseTime— время покупки.price— цена в минимальных единицах (в копейках).amountLabel— отформатированная цена покупки, включая валютный знак.currency— код валюты ISO 4217.-
developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации -
sandbox— флаг тестового платежа. Значениеtrue— тестовый платёж,false— реальный платёж. productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр). Идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).expirationDate- дата окончания действия подписки.gracePeriodEnabled- флаг, указывающий, активен ли Grace-период для подписки.
Статусная модель подписки
Покупка продукта
- При использовании одностадийного платежа покупка не требует подтверждения, денежные средства сразу списываются со счёта покупателя, а с разработчика удерживается комиссия. В таком случае, если требуется вернуть денежные средства клиенту (например, по какой-то причине нет возможности поставить продукт), возможен только возврат средств через RuStore Консоль, денежные средства возвращаются покупателю через несколько дней. Возвращается полная стоимость покупки, при этом удержанная комиссия разработчику не возмещает ся.
- В случае использования двухстадийного платежа сначала производится холдирование средств на счете покупателя. Комиссия в этом случае не удерживается. После холдирования покупка требует подтверждения или отмены. Комиссия с разработчика удерживается при подтверждении покупки. Отмена покупки означает снятие холда - денежные средства мгновенно снова доступны покупателю.
На данный момент покупка подписки (SubscriptionPurchase) может быть совершена только с использованием одностадийного платежа (PurchaseType.ONE_STEP).
Двухстадийная оплата доступна только для определенного набора способов оплаты (на текущий момент — только для карт и SberPay). Технологии СБП не поддерживают двухстадийную оплату. Если выбран способ оплаты, который не поддерживает холдирование, то покупка будет запущена по сценарию с одной стадией.
Оплата с выбором типа покупки
Для вызова покупки продукта с выбором стадийности оплаты используйте метод purchase.
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
Future<void> purchaseProduct() async {
final params = ProductPurchaseParams(
productId: 'productId',
orderId: null,
quantity: null,
developerPayload: null,
appUserId: null,
appUserEmail: null,
);
try {
final result = await RuStorePayClient.instance.purchaseInteractor.purchase(
params.productId,
quantity: params.quantity ?? 1,
orderId: params.orderId,
developerPayload: params.developerPayload,
appUserId: params.appUserId,
appUserEmail: params.appUserEmail,
preferredPurchaseType: PreferredPurchaseType.oneStep,
);
// Логика обработки успешного результата покупки
} on RuStoreProductPurchaseException {
// Обработка ошибки покупки продукта
} on RuStorePurchaseCancelledException {
// Обработка отмены покупки продукта
} catch (_) {
// Обработка ошибки
}
}
preferredPurchaseType— желаемый тип покупки: одностадийная (ONE_STEP) или двухстадийная (TWO_STEP).
Данный метод по умолчанию запускается по одностадийному сценарию оплаты (preferredPurchaseType = PreferredPurchaseType.ONE_STEP), т.е. без холдирования средств.
Для двухстадийной оплаты нужно указать preferredPurchaseType = PreferredPurchaseType.TWO_STEP. Двухстадийная оплата (т.е. оплата с холдированием средств) для данного метода не гарантирована и напрямую зависит от того, какой способ оплаты (карта, СПБ и др.) выбрал пользователь.
При запуске данного метода (с предпочитаемым preferredPurchaseType = twoStep), до тех пор пока пользователь не выберет способ оплаты, стадийность покупки будет UNDEFINED. Учитывайте данное поведение при обработке результатов отмены (ProductPurchaseCancelled) или ошибки (ProductPurchaseException) покупки.
Двухстадийная оплата (с холдированием средств)
Для вызова покупки продукта по двухстадийному сценарию используйте метод purchaseTwoStep.
При вызове данного метода пользователю будет доступен ограниченный набор способов оплаты — только те, которые поддерживают двухстадийную оплату.
На данный момент покупка подписки (SubscriptionPurchase) может быть совершена только с использованием одностадийного платежа (PurchaseType.ONE_STEP).
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
Future<void> purchaseTwoStep() async {
final params = ProductPurchaseParams(
productId: 'productId',
orderId: null,
quantity: null,
developerPayload: null,
appUserId: null,
appUserEmail: null,
);
try {
final result = await RuStorePayClient.instance.purchaseInteractor.purchaseTwoStep(
params.productId,
quantity: params.quantity ?? 1,
orderId: params.orderId,
developerPayload: params.developerPayload,
appUserId: params.appUserId,
appUserEmail: params.appUserEmail,
);
// Логика обработки успешного результата покупки
} on RuStoreProductPurchaseException {
// Обработка ошибки покупки продукта
} on RuStorePurchaseCancelledException {
// Обработка отмены покупки продукта
} catch (_) {
// Обработка ошибки
}
}
Структура параметров покупки
class ProductPurchaseParams {
final String productId;
final int? quantity;
final String? orderId;
final String? developerPayload;
final String? appUserId;
final String? appUserEmail;
const ProductPurchaseParams({
required this.productId,
this.quantity,
this.orderId,
this.developerPayload,
this.appUserId,
this.appUserEmail,
});
}
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Ес ли не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются.-
appUserId— внутренний ID пользователя в вашем приложении (опциональный параметр). Строка с максимальной длиной в 128 символов.tipНапример, данный параметр может использоваться для выявления случаев мошенничества в вашем приложении, что позволит повысить его безопасность.
appUserEmail— это необязательный параметр, позволяющий задать адрес электронной почты пользователя в вашем приложении. Если адрес электронной почты покупателя был указан при регистрации в приложении, его можно передать для автоматического заполнения поляemailпри отправке чека — как для платежей вне RuStore, так и для случаев, когда пользователь не авторизован в RuStore. Это избавляет пользователя от необходимости вручную вводить email, сокращает путь до покупки и способствует повышению конверсии.
Подтверждение покупки
Подтверждения требуют только покупки, которые были запущены по двухстадийному сценарию оплаты, т.е. с
холдированием средств. Такие покупки, после успешного холдирования будут находиться в статусе PurchaseStatus.paid..
Для списания средств с карты покупателя требуется подтверждение покупки.
Для этого вы должны использовать метод confirmTwoStepPurchase.
RuStorePayClient.instance.purchaseInteractor.confirmTwoStepPurchase(id).then((value) {
// Process success
});
id— идентификатор покупки.-
developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации
Отмена покупки
Через SDK можно отменять только те покупки, которые были запущены по двухстадийному сценарию оплаты, т.е. с холдированием средств. Такие покупки после успешного холдирования будут находиться в статусе PurchaseStatus.PAID. После отмены покупки будут переходить в статус PurchaseStatus.REVERSED.
Используйте отмену покупки в случаях, если после оплаты (холдирования средств) вы не можете предоставить покупателю товар.
Для отмены покупки (холда) используйте метод cancelTwoStepPurchase.
void cancelTwoStepPurchaseExample() {
RuStorePayClient.instance.purchaseInteractor
.cancelTwoStepPurchase('purchaseId')
.then((_) {
// Process success
})
.catchError((error) {
// Process error
});
}
purchaseId— идентификатор покупки.
Структура результата покупки
ProductPurchaseResult - результат успешной оплаты цифрового товара, подписки (для одностадийной оплаты) или успешного холдирования средств (для двухстадийной оплаты).
class ProductPurchaseResult {
final String? orderId;
final String purchaseId;
final String productId;
final String invoiceId;
final PurchaseType purchaseType;
final ProductType productType;
final int quantity;
final bool sandbox;
const ProductPurchaseResult({
this.orderId,
required this.purchaseId,
required this.productId,
required this.invoiceId,
required this.purchaseType,
required this.productType,
required this.quantity,
required this.sandbox,
});
}
ProductPurchaseResult— результат успешной оплаты цифрового товара (для одностадийной оплаты) или успешного холдирования средств (для двухстадийной оплаты).purchaseId- идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупке и серверной валидации подписки.productId- идентификатор приобретенного продукта, указанный при создании в консоли разработчика RuStore.invoiceId- идентификатор счета. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей в мобильном приложении RuStore.orderId- уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).purchaseType- тип покупки (ONE_STEP/TWO_STEP/UNDEFINED- одностадийная/двухстадийная/стадийность не определена).productType- тип продукта (NON_CONSUMABLE_PRODUCT- непотребляемый товар,CONSUMABLE_PRODUCT- потребляемый товар,SUBSCRIPTION- подписка).quantity- количество товара, заданное при старте покупки.sandbox- флаг, указывающий признак тестового платежа в песочнице. ЕслиTRUE- покупка совершена в режиме тестирования.
Обработка ошибок
Если в процессе оплаты возникает ошибка или пользователь отменяет покупку, выполнение метода оплаты (как с выбором типа покупки, так и двухстадийного метода) завершается с ошибкой:
ProductPurchaseException- ошибка покупки продукта.ProductPurchaseCancelled- ошибка, вызванная отменой покупки продукта (пользователь закрыл платежную шторку) до получения результата покупки. В таком случае рекомендуется дополнительно проверить статус покупки методом получения информации о покупке.
Структура ошибки и отмены покупки:
class ProductPurchaseException implements Exception {
final String? orderId;
final String? purchaseId;
final String? productId;
final String? invoiceId;
final int? quantity;
final PurchaseType? purchaseType;
final ProductType? productType;
final bool? sandbox;
final Object cause;
const ProductPurchaseException({
this.orderId,
this.purchaseId,
this.productId,
this.invoiceId,
this.quantity,
this.purchaseType,
this.productType,
this.sandbox,
required this.cause,
});
String toString() => 'Error purchase product: $cause';
}
class ProductPurchaseCancelled implements Exception {
final String? purchaseId;
final PurchaseType? purchaseType;
final ProductType? productType;
const ProductPurchaseCancelled({
this.purchaseId,
this.purchaseType,
this.productType,
});
String toString() => 'Purchase product is cancelled';
}
purchaseId— идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупке.productId— идентификатор приобретённого продукта, указанный при создании в консоли разработчика RuStore.invoiceId— идентификатор счёт а. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей в мобильном приложении RuStore.orderId— уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).purchaseType— тип покупки (ONE_STEP/TWO_STEP/UNDEFINED— одностадийная/двухстадийная/стадийность не определена).productType- тип продукта (NON_CONSUMABLE_PRODUCT- непотребляемый товар,CONSUMABLE_PRODUCT- потребляемый товар,SUBSCRIPTION- подписка).quantity— количество товара, заданное при старте покупки.
Валидация покупки на сервере
Если вам необходимо произвести валидацию успешной покупки на сервере RuStore, вы можете использовать subscriptionToken в ProductPurchaseResult.SuccessProductPurchaseResult, возвращаемой при успешной покупке продукта.
Если вам необходимо произвести валидацию успешной покупки в RuStore, вы можете использовать публичные API-интерфейсы валидации (https://www.rustore.ru/help/work-with-rustore-api/api-subscription-payment/v2-purchase-invoiceid). Для валидации продуктов и подписок используются разные методы:
- Для валидации покупки продукта используйте
invoiceIdиз моделиProductPurchaseResult, возвращаемой после завершения покупки. - Для валидации покупки подписки используйте
purchaseIdиз моделиProductPurchaseResult, возвращаемой после завершения покупки.
Тип приобретённого продукта можно определить по данным, полученным в ответе ProductPurchaseResult.
Также можно получить subscriptionToken в сущности Purchase. Сущность Purchase можно получить, используя метод getPurchases().
class ProductPurchaseParams {
final String productId;
const ProductPurchaseParams(this.productId);
}
Future<void> exampleInvoiceFromResult() async {
final params = ProductPurchaseParams('productId');
final result = await RuStorePayClient.instance.purchaseInteractor.purchase(
params.productId,
preferredPurchaseType: PreferredPurchaseType.twoStep,
);
switch (result.productType) {
case ProductType.consumable:
case ProductType.nonConsumable:
final invoiceId = result.invoiceId;
yourApi.validateProduct(invoiceId);
break;
case ProductType.subscription:
final purchaseId = result.purchaseId;
yourApi.validateSubscription(purchaseId);
break;
default:
// необязательная обработка неопределённого типа
break;
}
}
Future<void> exampleSubscriptionTokenFromPurchases() async {
final purchases =
await RuStorePayClient.instance.purchaseInteractor.getPurchases();
for (final purchase in purchases) {
if (purchase is SubscriptionPurchase) {
final purchaseId = purchase.purchaseId;
yourApi.validateSubscription(purchaseId);
} else {
final invoiceId = purchase.invoiceId;
yourApi.validateProduct(invoiceId);
}
}
}
RuStoreUtils
RuStoreUtils — это блок в нативном SDK, содержащий набор публичных методов, предназначенных для взаимодействия с приложением RuStore на устройстве пользователя.
Для доступа к методам блока в среде Unity используется синглтон класса RuStoreCoreClient.
Метод IsRuStoreInstalled проверяет наличие приложения RuStore н а устройстве пользователя.
if (RuStorePayClient.Instance.IsRuStoreInstalled()) {
// RuStore установлен на устройстве пользователя
} else {
// RuStore не установлен на устройстве пользователя
}
Метод openRuStoreDownloadInstruction открывает веб-страницу для скачивания мобильного приложения RuStore.
RuStoreCoreClient.Instance.openRuStoreDownloadInstruction();
Метод openRuStore запускает мобильное приложение RuStore. При вызове данного метода, в случае отсутствия установленного приложения RuStore, будет отображено Toast уведомление с сообщением "Не удалось открыть приложение".
RuStoreCoreClient.Instance.openRuStore();
Метод openRuStoreAuthorization запускает мобильное приложение RuStore для авторизации. После успешной авторизации пользователя приложение RuStore автоматически закрывается. При вызове данного метода, в случае отсутствия установленного приложения RuStore, будет отображено Toast уведомление с сообщением "Не удалось открыть приложение".
RuStoreCoreClient.Instance.openRuStoreAuthorization();
Использование RuStoreUtils для проверки платежных сценариев
Кейс применения RuStoreUtils для проверки наличия RuStore на устройстве и работы с авторизацией пользователя рассмотрен в статье Приём платежей без установки RuStore.
В статье приведены:
-
Сценарии работы с покупками при отсутствии установленного RuStore;
-
Примеры последовательного вызова методов проверки установки и авторизации через RuStoreUtils;
-
Особенности поведения SDK в разных условиях (наличие/отсутствие RuStore, авторизация пользователя и др.).
Список ошибок
RuStorePaymentNetworkException - ошибка сетевого взаимодействия SDK. В модели ошибки возвращается код ошибки (поле code), по которому можно определить причину ошибки. Таблица с кодами ошибок доступна в разделе коды ошибок.
Поле message содержит описание причины ошибки.
class RuStorePaymentNetworkException implements Exception {
final String? code;
final String id;
final String message;
final Object? cause;
const RuStorePaymentNetworkException({
this.code,
required this.id,
required this.message,
this.cause,
});
String toString() => message;
}
RuStorePaymentNetworkException— о шибка сетевого взаимодействия SDK;RuStorePaymentCommonException— общая ошибка SDK;RuStorePayClientAlreadyExist— ошибка повторной инициализации SDK;RuStorePayClientNotCreated— попытка обратиться к публичным интерфейсам SDK до момента её инициализации;RuStorePayInvalidActivePurchase— запущен процесс оплаты неизвестного типа продукта;RuStorePayInvalidConsoleAppId— не задан обязательный параметрconsole_application_idдля инициализации SDK;RuStorePaySignatureException— неверная сигнатура ответа. Возникает при попытке совершить мошеннические действия;EmptyPaymentTokenException— ошибка получения платёжного токена;InvalidCardBindingIdException— ошибка оплаты сохранённой картой;ApplicationSchemeWasNotProvided— не указана схема для обратного диплинка;ProductPurchaseException- ошибка покупки продукта. Структура модели представлена в разделе структура результата покупки;ProductPurchaseCancelled- произошла отмена покупки продукта (пользователь закрыл платёжную шторку). Структура модели представлена в разделе структура результата покупки;ProductPurchaseException— ошибка покупки продукта;RuStoreNotInstalledException— на устройстве пользователя не установлен RuStore;RuStoreOutdatedException— установленная на устройстве версия RuStore не поддерживает платежи;RuStoreUserUnauthorizedException— пользователь не авторизован в RuStore;RuStoreApplicationBannedException— приложение заблокировано в RuStore;RuStoreUserBannedException— пользователь заблокирован в RuStore.
Коды ошибок
| Код ошибки | Описание |
|---|---|
4000001 | Запрос сформирован некорректно: отсутствует или неверно заполнен обязательный параметр, неверный формат данных. |
4000002, 4000016, 4040005 | Приложение не найдено. |
4000003 | Приложение заблокировано. |
4000004 | Подпись приложения не совпадает с зарегистрированной. |
4000005 | Компания не найдена. |
4000006 | Компания заблокирована. |
4000007 | Монетизация компании отключена или неактивна. |
4000014 | Продукт не найден. |
4000015 | Продукт не опубликован. |
4000017 | Некорректный параметр quantity. |
4000018 | Превышен лимит покупок. |
4000020 | Продукт уже приобретен. |
4000021 | Незавершенная покупка продукта. |
4000022 | Покупка не найдена. |
4000025 | Не найден подходящий способ оплаты. |
4000026 | Неверный тип покупки для подтверждения (должна быть двухстадийная оплата). |
4000027 | Неверный статус покупки для подтверждения. |
4000028 | Неверный тип покупки для отмены (должна быть двухстадийная оплата). |
4000029 | Неверный статус покупки для отмены. |
4000030 | Выписанный токен не соответствует покупаемому товару. |
4000041 | У пользователя уже есть активная подписка для данного кода продукта. |
4010001 | Доступ к запрашиваему ресурсу запрещен (неавторизовано). |
4010002 | Время жизни токена истекло. |
4010003 | Платежный токен невалиден. |
4030001 | Не передан платежный токен. |
4030002 | Пользователь заблокирован по требованиям безопасности. |
4040002, 4040003, 4040004 | Ошибка платежной системы. |
5000*** | Внутренняя ошиб ка. |