跳到主要内容

SDK in-app платежей для Flutter (версия 4.0.0)

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

提示

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

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

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

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

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

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

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

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

flutter pub add flutter_rustore_billing

Эта команда добавит строчку в файл pubspec.yaml.

dependencies: flutter_rustore_billing: ^4.0.0

Deeplink в RuStore SDK платежей нужна для корректной работы со сторонними приложениями оплаты. Она помогает пользователям быстрее совершать покупки в стороннем приложении и возвращаться в ваше приложение.

Для настройки работы с deeplink в вашем приложении и RuStore SDK, укажите deeplinkScheme внутри вашего AndroidManifest файла и переопределите метод onNewIntent вашего Activity.

AndroidManifest.xml
<activity
android:name=".sample.MainActivity">
<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.

信息

Схема, указанная в AndroidManifest файле должна совпадать со схемой, которую вы указываете в методе create RuStore SDK платежей.

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

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

Для инициализации вызовите метод RustoreBillingClient.initialize().
RustoreBillingClient.initialize(
"123456", //consolApplicationId
"yourappscheme", //deeplinkScheme
true //allowNativeErrorHandling
).then((value) {
print("initialize success: $value");
}, onError: (err) {
print("initialize err: $err");
}
);
Где в RuStore Консоль отображаются идентификаторы приложений?
  1. Перейдите на вкладку Приложения и выберите нужное приложение.
  2. Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между apps/ и /versions. Например, для URL-адреса https://console.rustore.ru/apps/123456/versions ID приложения — 123456.

备注

ApplicationId, указанный в build.gradle, должен совпадать с applicationId APK-файла, который вы публиковали в RuStore Консоль.

  • deeplinkScheme — схема deeplink, необходимая для возврата в ваше приложение после оплаты через стороннее приложение (например, SberPay или СБП). SDK генерирует свой хост к данной схеме.
备注
Схема deeplink, передаваемая в yourappscheme, должна совпадать со схемой, указанной в AndroidManifest.xml (подробнее см. Обработка deeplink).
  • allowNativeErrorHandling — разрешить обработку ошибок в нативном SDK (см. подробнее в разделе Обработка ошибок).

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

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

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

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

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

Для проверки доступности платежей используйте метод RustoreBillingClient.available().Если все указанные выше условия выполняются, возвращается true.

RustoreBillingClient.available().then((value) { 
print("available success $value");
}, onError: (err) {
print("available err: $err");
}
);

Работа с SDK

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

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

RustoreBillingClient.products(ids).then((response) {
for (final product in response.products) {
print(product?.productId);
}
}, onError: (err) {
print("products err: $err");
}
);

ids: List<String?> — список идентификаторов продуктов. В нём не должно быть более 100 позиций.

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

  1. Откройте RuStore Консоль.
  2. Перейдите на вкладку Приложения.
  3. Выберите нужное приложение.
  4. В левом боковом меню выберите раздел Монетизация.
  5. Выберите тип товара: Подписки или Разовые покупки.
  6. Скопируйте идентификаторы нужных товаров. Это и есть id продуктов.

Метод возвращает ProductsResponse

class ProductsResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<Product?> products;
List<DigitalShopGeneralError?> errors;
}
  • code — код ответа.
  • errorMessage — сообщение об ошибке для пользователя.
  • errorDescription — расшифровка сообщения об ошибке.
  • traceId — идентификатор ошибки.
  • errors — список ошибок для запрошенных продуктов.
  • products — список продуктов.

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

class DigitalShopGeneralError {
String? name;
int ? code;
String? description
}
  • name – имя ошибки.
  • code — код ошибки.
  • description – описание ошибки.

Структура продукта Product

class Product {
String productId;
String? productType;
String productStatus;
String? priceLabel;
int ? price;
String? currency;
String? language;
String? title;
String? description;
String? imageUrl;
String? promoImageUrl;
Subscription? 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.

Структура подписки Subscription

class Subscription {
SubscriptionPeriod? subscriptionPeriod;
SubscriptionPeriod? freeTrialPeriod;
SubscriptionPeriod? gracePeriod;
String? introductoryPrice;
String? introductoryPriceAmount;
SubscriptionPeriod? introductoryPricePeriod;
}
  • subscriptionPeriod — период подписки.
  • freeTrialPeriod — пробный период подписки.
  • gracePeriod — льготный период подписки.
  • introductoryPrice — отформатированная вступительная цена подписки, включая знак валюты, на языке product:language.
  • introductoryPriceAmount — вступительная цена в минимальных единицах валюты (в копейках).
  • introductoryPricePeriod — расчётный период вступительной цены.

Структура периода подписки SubscriptionPeriod

class SubscriptionPeriod {
int years;
int months;
int days;
}
  • years — количество лет.
  • months — количество месяцев.
  • days — количество дней.

Покупка продукта

Для вызова покупки продукта используйте метод RustoreBillingClient.purchase(id).

RustoreBillingClient.purchase(id).then((response) {
print("purchase success: $response");
}, onError: (err) {
print("purchase err: $err");
}
);

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

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

class PaymentResult {
SuccessInvoice? successInvoice;
InvalidInvoice? invalidInvoice;
SuccessPurchase? successPurchase;
InvalidPurchase? invalidPurchase;
}

Структура SuccessInvoice

class SuccessInvoice {
String invoiceId;
String finishCode;
}

Структура InvalidInvoice

class InvalidInvoice {
String? invoiceId;
}

Структура SuccessPurchase

class SuccessPurchase {
String finishCode;
String? orderId;
String purchaseId;
String productId;
}

Структура InvalidPurchase

class InvalidPurchase {
String? purchaseId;
String? invoiceId;
String? orderId;
int? quantity;
String? productId;
int? errorCode;
}
  • SuccessInvoice — платежи завершились с результатом.
  • InvalidInvoice — платежи завершились без указания номера счёта. Вероятно, они были запущены с некорректным номером счёта (пустая строка, например).
  • SuccessPurchase — результат успешного завершения покупки цифрового товара.
  • InvalidPurchase — при оплате цифрового товара платежи завершились с ошибкой.

Возможные статусы, которые может содержать finishCode

  • SUCCESSFUL_PAYMENT — успешная оплата.
  • CLOSED_BY_USER — отменено пользователем.
  • UNHANDLED_FORM_ERROR — неизвестная ошибка.
  • PAYMENT_TIMEOUT — ошибка оплаты по таймауту.
  • DECLINED_BY_SERVER — отклонено сервером.
  • RESULT_UNKNOWN — неизвестный статус оплаты.

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

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

Тип/СтатусINVOICE_CREATEDCONFIRMEDPAIDPAUSED
CONSUMABLE++
NON-CONSUMABLE++
SUBSCRIPTION+++
备注

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

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

RustoreBillingClient.purchases().then((response) {
for (final product in response.purchases) {
print(product?.purchaseId);
}
}, onError: (err) {
print("purchases err: $err" );
}
);

Метод возвращает PurchasesResponse (см. ниже).

class PurchasesResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<Purchase?> purchases;
List<DigitalShopGeneralError?> errors;
}
  • code — код ответа.
  • errorMessage — сообщение об ошибке для пользователя.
  • errorDescription — расшифровка сообщения об ошибке.
  • errors — список ошибок для запрошенных продуктов.
  • purchases — список запрошенных покупок.

Структура ошибки DigitalShopGeneralError (см. ниже).

class DigitalShopGeneralError {
String? name;
int ? code;
String? description;
}
  • name – имя ошибки.
  • code — код ошибки.
  • description – описание ошибки.
class Purchase {
String? purchaseId;
String? productId;
String? description;
String? language;
String? purchaseTime;
String? orderId;
String? amountLabel;
int ? amount;
String? currency;
int ? quantity;
String? purchaseState;
String? developerPayload;
}

Структура покупки Purchase (см. ниже).

  • purchaseId — идентификатор покупки.
  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).
  • description — описание на языке language.
  • language — язык, указанный с помощью BCP 47 кодирования.
  • purchaseTime — время покупки.
  • orderId — уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.
  • amountLable — отформатированная цена покупки, включая валютный знак.
  • amount — цена в минимальных единицах валюты.
  • currency — код валюты ISO 4217.
  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).
  • purchaseState — состояние покупки.
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.

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

Для получения информации о покупке, используйте метод purchaseInfo.
RustoreBillingClient.purchaseInfo(purchaseId).then((purchase) {
print(purchase);
}, onError: (err) {
print("Error getPurchaseInfo: $err");
}
);

Структура покупки Purchase (см. ниже).

class Purchase {
String? purchaseId;
String? productId;
String? description;
String? language;
String? purchaseTime;
String? orderId;
String? amountLabel;
int ? amount;
String? currency;
int ? quantity;
String? purchaseState;
String? developerPayload;
}
  • purchaseId — идентификатор покупки.
  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).
  • description — описание на языке language.
  • language — язык, указанный с помощью BCP 47 кодирования.
  • purchaseTime — время покупки.
  • orderId — уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.
  • amountLable — отформатированная цена покупки, включая валютный знак.
  • amount — цена в минимальных единицах валюты.
  • currency — код валюты ISO 4217.
  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).
  • purchaseState — состояние покупки.
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при инициализации процесса покупки.

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

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

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

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

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

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

img

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

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

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

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

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

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

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

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

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

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

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

RustoreBillingClient.confirm(id).then((response) {
print( "confirm success: $response" );
}, onError: (err) {
print( "confirm err: $err" );
}
);
  • id — идентификатор покупки.

Метод возвращает ConfirmPurchaseResponse (см. ниже).

class ConfirmPurchaseResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<DigitalShopGeneralError?> errors;
}
  • code — код ответа.
  • errorMessage — сообщение об ошибке для пользователя.
  • errorDescription — расшифровка сообщения об ошибке.
  • traceId — идентификатор ошибки.
  • errors — список ошибок для запрошенных продуктов.

Структура ошибки DigitalShopGeneralError (см. ниже).

class DigitalShopGeneralError {
String? name;
int ? code;
String? description;
}
  • name – имя ошибки.
  • code — код ошибки.
  • description – описание ошибки.

Валидация покупок на сервере

Если вам необходимо произвести валидацию успешной покупки на сервере методами API RuStore, вы можете использовать subscriptionToken в PurchaseResult, возвращаемой purchaseProduct при успешной покупке продукта.

SubscriptionToken состоит из invoiceId покупки и userId, записанных через точку: $invoiceId.$userId.

Также можно получить subscriptionToken в сущности Purchase. Сущность Purchase можно получить, используя метод purchases().

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

Логирование включено по умолчанию внутри flutter sdk. Логи вы можете смотреть по тегу RuStoreFlutterBillingPlugin.

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

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

  • RuStoreNotInstalledException — на устройстве пользователя не установлен RuStore;
  • RuStoreOutdatedException — версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;
  • RuStoreUserUnauthorizedException — пользователь не авторизован в RuStore;
  • RuStoreApplicationBannedException — приложение заблокировано в RuStore;
  • RuStoreUserBannedException — пользователь заблокирован в RuStore;
  • RuStoreException — базовая ошибка RuStore, от которой наследуются остальные ошибки.

По умолчанию в плагине включена нативная обработка ошибок, в случае возникновения ошибки выполняются эти действия:

  • Вызовется соответствующий обработчик ошибки.

  • Ошибка передаётся в метод resolveForBilling нативного SDK. Это нужно, чтобы показать пользователю диалог с ошибкой.

Метод resolveForBilling
fun RuStoreException.resolveForBilling(context: Context)

Чтобы отключить передачу ошибки в нативный SDK, вызовите функцию offNativeErrorHandling.

Запрет нативной обработки ошибок
RustoreBillingClient.offNativeErrorHandling();