Перейти к основному содержимому

SDK Платежи in-app для Flutter (версия 8.0.0)

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

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

  • Если вы переходите на Pay SDK с billingClient SDK, ознакомьтесь с инструкцией по переходу. Подробности о Pay SDK можно узнать тут.

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

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

flutter pub add flutter_rustore_pay

Обработка deeplink в RuStore SDK позволяет эффективно взаимодействовать со сторонними приложениями, при проведении платежей через банковские приложения (СБП, SberPay, T-Pay и др.). Это позволяет перевести пользователя на экран оплаты, а после завершения транзакции — вернуть в ваше приложение.

Для настройки работы с deeplink в вашем приложении и Pay SDK, укажите deeplinkScheme с помощью sdk_pay_scheme_value в AndroidManifest.xml файле.

Внимание

При использовании deeplinks указание схемы является обязательным. При попытке платежа без указания схемы будет возникать ошибка.

Указание deeplinkScheme:

AndroidManifest.xml
<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="singleTask".

Указание launchMode:

AndroidManifest.xml
<activity
android:name=".YourBillingActivity"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">

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

Перед вызовом методов библиотеки необходимо выполнить ее инициализацию. Сама инициализация происходит автоматически, но для работы SDK в вашем файле AndroidManifest.xml необходимо прописать console_app_id_value.

AndroidManifest.xml
<meta-data
android:name="console_app_id_value"
android:value="@string/CONSOLE_APPLICATION_ID" />

В strings.xml замените строку с вашим app_id.

strings.xml
<string name="CONSOLE_APPLICATION_ID">your_app_id</string>

CONSOLE_APPLICATION_ID — идентификатор приложения из RuStore консоли.

Где в RuStore Консоль отображаются идентификаторы приложений?
  1. Перейдите на вкладку Приложения и выберите нужное приложение.
  2. Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между apps/ и /versions. Например, для URL-адреса https://console.rustore.ru/apps/123456/versions ID приложения — 123456.

Важно
  • ApplicationId, указанный в build.gradle, должен совпадать с applicationId APK-файла, который вы публиковали в RuStore Консоль.
  • Подпись keystore должна совпадать с подписью, которой было подписано приложение, опубликованное в RuStore Консоль. Убедитесь, что используемый buildType (пр. debug) использует такую же подпись, что и опубликованное приложение (пр. release).

информация

В целях безопасности, SDK устанавливает android:usesCleartextTraffic="false" по умолчанию, чтобы предотвратить передачу данных по незащищенному HTTP и защитить от атак типа "Man-in-the-Middle". Если ваше приложение требует использования HTTP, вы можете изменить этот атрибут на true, но делайте это на свой страх и риск, так как это увеличивает шанс перехвата и подмены данных. Мы рекомендуем разрешать незащищенный трафик только в исключительных случаях и для доверенных доменов, предпочитая HTTPS для всех сетевых взаимодействий.

Методы SDK

В SDK доступны 2 публичных интерактора:

  • PurchaseInteractor — интерактор, который позволяет работать с платежами и имеет несколько публичных методов:
    • getPurchase(purchaseId: PurchaseId): Task<Purchase> - позволяет получить информацию о покупке по ее идентификатору;
    • getPurchases(): Task<List<Purchase>> - позволяет получить покупки пользователя. В списке возвращаются покупки в статусе CONFIRMED для непотребляемых товаров и PAID (статус, означающий холдирование средств и ожидающих подтверждения покупки со стороны разработчика);
    • getPurchaseAvailability(): Task<PurchaseAvailabilityResult> - возвращает результат доступности работы с платежами;
    • consumePurchase(purchaseId: PurchaseId, developerPayload: DeveloperPayload? = null) — позволяет совершить потребление покупки (только для потребляемых товаров).
  • ProductInteractor — интерактор, который позволяет работать с продуктами и имеет несколько публичных методов:
    • getProducts(productsId: List<ProductId>): Task<List<Product>>— позволяет получить информацию по продуктам по их ID.
      (Важно! Метод имеет ограничение в 1000 продуктов)
    • purchase(params: ProductPurchaseParams): Task<ProductPurchaseResult> — позволяет совершить покупку продукта

Также доступен RuStoreUtils — блок, включающий набор публичных методов:

  • isRuStoreInstalled — проверки наличия приложения RuStore на девайсе пользователя;
  • openRuStore — запускает мобильное приложение RuStore;
  • openRuStoreAuthorization — запускает мобильное приложение RuStore для авторизации, после успешной авторизации пользователя мобильное приложение RuStore автоматически закроется;
  • openRuStoreDownloadInstruction — открывает веб-страницу для скачивания мобильного приложения RuStore.

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

Для получения продуктов, добавленных в ваше приложение через 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 Консоль отображаются идентификаторы продуктов?
  1. Перейдите на вкладку Приложения и выберите нужное приложение.
  2. Выберите Монетизация в меню слева.
  3. Выберите тип товара: Подписки или Разовые покупки.
  4. Скопируйте идентификаторы нужных товаров.

Метод возвращает список продуктов. Ниже представлена модель продукта.

class Product {
String productId;
ProductType type;
String amountLabel;
int? price;
String currency;
String imageUrl;
String title;
String? description;
}
  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).
  • type — тип продукта. CONSUMABLE/NON-CONSUMABLE (потребляемый/непотребляемый).
  • amountLabel — отформатированная цена покупки, включая валютный знак.
  • price — цена в минимальных единицах (в копейках).
  • currency — код валюты ISO 4217.
  • title — название продукта на языке language.
  • description — описание на языке language.
  • imageUrl — ссылка на картинку.

Структура ProductType.

enum ProductType {
consumable,
nonConsumable,
}
  • consumable — потребляемый (можно купить много раз, например: кристаллы в приложении);
  • nonConsumable — непотребляемый (можно купить один раз, например: отключение рекламы в приложении);

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

Подсказка

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

В таком случае, если требуется вернуть денежные средства клиенту (например, по какой-то причине нет возможности выдать продукт), возможен только возврат средств через консоль разработчика, денежные средства возвращаются покупателю через несколько дней. Возвращается полная стоимость покупки, при этом удержанная комиссия разработчику не возмещается.

Одностадийная оплата (без холдирования средств)

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

Вызов метода покупки продукта
RuStorePayClient.instance.purchaseInteractor
.purchase(id).then((value) {
// Process success
});
  • У метода есть не опциональные и опциональные параметры:
  • productId - идентификатор продукта, который требуется приобрести (обязательный параметр).
  • quantity - количество продуктов - опционально. Если не указывать, то будет подставлено значение 1. Применимо только для покупки потребляемых товаров.
  • orderId - идентификатор заказа, создается на стороне приложения - опционально. Если не указан, то генерируется автоматически. Максимальная длина 150 символов
  • developerPayload - дополнительная информация от разработчика приложения (опционально). Максимальная длина 250 символов. Символы не экранируются.
  • appUserId - внутренний ID пользователя в приложении - опционально. Максимальная длина 128 символов
  • preferredPurchaseType - желаемый тип покупки - одностадийная (oneStep) или двухстадийная (twoStep) (опциональный параметр, по умолчанию oneStep).

Структура PreferredPurchaseType:

enum PreferredPurchaseType {
oneStep,
twoStep
}

Метод возвращает ProductPurchaseResult:

Данный метод по умолчанию запускается по одностадийному сценарию оплаты (preferredPurchaseType = PreferredPurchaseType.oneStep), т.е. без холдирования средств. Для двухстадийной оплаты нужно указать preferredPurchaseType = PreferredPurchaseType.TWO_STEP. двухстадийная оплата (т.е. оплата с холдированием средств) для данного метода - негарантированная, и напрямую будет зависеть от того, какой способом оплаты (карта, СПБ и др.) будет выбран пользователем.

ВАЖНО!

Не все способы оплаты поддерживают двухстадийную оплату.

Двухстадийная оплата (с холдированием средств)

В случае использования двухстадийного платежа сначала производится холдирование средств на счете покупателя. Комиссия в этом случае не удерживается. После холдирования покупка требует подтверждения или отмены. Комиссия с разработчика удерживается при подтверждении покупки. Отмена покупки означает снятие холда - денежные средства мгновенно снова доступны покупателю.

При вызове данного метода пользователю будет доступен ограниченный набор способов оплаты - только те, которые поддерживают двухстадийную оплату

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

Вызов метода покупки продукта
RuStorePayClient.instance.purchaseInteractor.purchaseTwoStep(id).then((value) {
// Process success
});
  • У метода есть не опциональные и опциональные параметры:
  • productId - идентификатор продукта (обязательный параметр).
  • quantity - количество продуктов - опционально. Если не указывать, то будет подставлено значение 1. Применимо только для покупки потребляемых товаров.
  • orderId - идентификатор заказа, создается на стороне приложения. (опционально. Если не указан, то генерируется автоматически). Максимальная длина 150 символов
  • developerPayload - дополнительная информация от разработчика приложения (опционально). Максимальная длина 250 символов. Символы не экранируются.
  • appUserId - внутренний ID пользователя в приложении - опционально. Максимальная длина 128 символов

Метод возвращает ProductPurchaseResult:

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

class ProductPurchaseResult {
Success? success;
Cancelled? cancelled;
Failure? failure;
}

Структура Success:

class Success {
String? orderId;
String purchaseId;
String productId;
String invoiceId;
PurchaseType purchaseType;
bool sandbox;
}

Структура Cancelled:

class Cancelled {
String? purchaseId;
PurchaseType purchaseType;
}

Структура Failure:

class Failure {
String? orderId;
String? purchaseId;
String? productId;
String? invoiceId;
int? quantity;
String errorMessage;
PurchaseType purchaseType
}
  • SuccessProductPurchaseResult - результат успешного завершения покупки цифрового товара.
  • FailureProductPurchaseResult - результат ошибки покупки цифрового товара.
  • CancelProductPurchaseResult - платежный диалог закрыт до получения результата покупки. Состояние покупки неизвестно. Рекомендуем запросить статус покупки отдельно методом получения информации о покупке.
  • purchaseId - идентификатор покупки. Используется для получения информации о покупке в SDK методом получения информации о покупке
  • productId - идентификатор приобретенного продукта, указанный при создании в консоли разработчика RuStore.
  • invoiceId - идентификатор счета. Используется для серверной валидации платежа, поиска платежей в консоли разработчика, а также отображается покупателю в истории платежей в мобильном приложении RuStore
  • orderId - уникальный идентификатор оплаты, указанный разработчиком или сформированный автоматически (uuid).
  • purchaseType - тип покупки (ONE_STEP/TWO_STEP - одностадийная\двухстадийная)
  • sandbox - флаг, указывающий признак тестового платежа в песочнице. Если TRUE - покупка совершена в режиме тестирования
  • errorMessage - сообщение с причиной ошибки

Подтверждение покупки

Подтверждения требуют только покупки, которые были запущены по двухстадийному сценарию оплаты, т.е. с холдированием средств. Такие покупки, после успешного холдирования будут находиться в статусе PurchaseStatus.paid..

Для списания средств с карты покупателя требуется подтверждение покупки. Для этого вы должны использовать метод confirmTwoStepPurchase.

RuStorePayClient.instance.purchaseInteractor.confirmTwoStepPurchase(id).then((value) {
// Process success
});
  • id — идентификатор покупки.
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации

Отмена покупки

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

Такие покупки после успешной оплаты будут находиться в статусе PurchaseStatus.paid. После отмены покупки будут переходить в статус PurchaseStatus.reversed.

Используйте отмену покупки в случаях, если после оплаты (холдирования средств) вы не можете предоставить покупателю товар.

Для отмены покупки (холдирования) используйте метод cancelTwoStepPurchase:

RuStorePayClient.instance.purchaseInteractor.cancelTwoStepPurchase(id).then((value) {
// Process success
});
  • id — идентификатор покупки.

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

Для получения информации о покупке, используйте метод getPurchase.
RuStorePayClient.instance.purchaseInteractor.getPurchase(purchaseId).then((purchase) {
// Process success
});

Метод возвращает информацию о конкретной покупке в любом статусе. Ниже представлена модель покупки.

class Purchase {
String purchaseId;
String productId;
String invoiceId;
String? orderId;
PurchaseType purchaseType;
ProductType productType;
String description;
String? purchaseTime;
int price;
String amountLabel;
String currency;
int quantity;
PurchaseStatus status;
String? subscriptionToken;
String? developerPayload;
}

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

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

Для получения списка покупок необходимо использовать метод getPurchases({ProductType? productType})

Данный метод поддерживает необязательную фильтрацию по типу товаров (потребляемые или непотреблямые товары), а также по статусу покупки (поддерживаются только статусы PAID и CONFIRMED). По умолчанию фильтр выключен и вернет все покупки пользователя (вне зависимости от типа товара) в статусах PAID и CONFIRMED. Статус PAID означает успешное холдирование средств, покупка ожидает подтверждения покупки со стороны разработчика.

RuStorePayClient.instance.purchaseInteractor.getPurchases().then((purchases) {
// Process success
});
class Purchase {
String purchaseId;
String productId;
String invoiceId;
String? orderId;
PurchaseType purchaseType;
ProductType productType;
String description;
String? purchaseTime;
int price;
String amountLabel;
String currency;
int quantity;
PurchaseStatus status;
String? developerPayload;
bool sandbox;
}
  • purchaseId — идентификатор покупки.
  • productId — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).
  • invoiceId — идентификатор счета.
  • orderId — уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.
  • purchaseType — тип покупки.
  • productType — тип продукта (потребляемый / непотребляемый / подписка): CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.
  • description — описание на языке language.
  • purchaseTime — время покупки.
  • price — цена в минимальных единицах (в копейках).
  • amountLable — отформатированная цена покупки, включая валютный знак.
  • currency — код валюты ISO 4217.
  • quantity — количество продукта. Необязательный параметр со стандартным значением 1. Применим только к покупке потребляемых товаров.
  • purchaseState — состояние покупки:
    • INVOICE_CREATED — создан счет на оплату, покупка ожидает оплаты;
    • CANCELLED — покупка отменена покупателем;
    • PROCESSING — запущена оплата;
    • REJECTED — покупка отклонена (например, ввиду недостатка средств)
    • EXPIRED — истекло время на оплату покупки
    • PAID — только для двухстадийной оплаты, промежуточный статус, средства на счете покупателя захолдированы, покупка ожидает подтверждения от разработчика;
    • CONFIRMED — покупка успешно оплачена;
    • REFUNDING — инициирован возврат, запрос отправлен в эквайер;
    • REFUNDED — запрос на возврат средств за покупку совершен успешно. Деньги будут возвращены пользователю в течение 10 рабочих дней.;
    • REVERSED — только для двухстадийной оплаты, покупка была отменена разработчиком или не было произведено подтверждение покупки в течение 6 часов, холдирование средств отменено.
  • developerPayload — строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации.

Структура PurchaseType.

enum PurchaseType {
oneStep,
twoStep,
}

Проверка наличия RuStore на устройстве

Метод isRuStoreInstalled применяется для проверки, установлен ли RuStore на устройстве пользователя. Эта проверка нужна для реализации корректной логики работы с товарами и покупками. Приведенные ниже методы SDK платежей требуют авторизации пользователя:

Если на устройстве пользователя не установлен RuStore, всякий раз будет отображаться шторка веб-авторизации, что может негативно сказаться на пользовательском опыте. Таким образом, если проверка показывает, что приложение RuStore устройстве пользователя не установлено, имеет смысл сократить количество запросов, которые требуют авторизации (подробнее см. в разделе Прием платежей без установки RuStore).

public fun isRuStoreInstalled(context: Context): Boolean

Определение наличия авторизации у пользователя

Для проверки статуса авторизации пользователя, вызовите метод getUserAuthorizationStatus у UserInteractor. Результатом выполнения метода является класс UserAuthorizationStatus. Доступно 2 значения:

  • AUTHORIZED - пользователь авторизован в RuStore
  • UNAUTHORIZED - пользователь неавторизован в RuStore. Данное значение также вернется если у пользователя нет установленного RuStore на девайсе.
RuStorePayClient.instance.userInteractor.getUserAuthorizationStatus().then((value) {
if (value case Authorized _) {
// Process authorized
} else if (value case Unauthorized _) {
// Process unauthorized
}
});

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

Для проверки доступности платежей, вызовите метод getPurchaseAvailability. При его вызове проверяются следующие условия.

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

Если все указанные выше условия выполняются, возвращается PurchaseAvailabilityResponse.Available.В противном случае возвращается PurchaseAvailabilityResponse.Unavailable(val cause: Throwable), где cause — это ошибка о невыполненном условии.

Вызов метода getPurchaseAvailability
RuStorePayClient.instance.purchaseInteractor.getPurchaseAvailability().then((value) {
if (value case Available _) {
// Process purchases available
} else if (value case Unavailable unavailable) {
// Process purchases unavailable
}
});

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

Статусная модель одностадийного платежа.



Статусная модель двухстадийного платежа.



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

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

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

RuStorePayClient.instance.getPurchases().then((response) {
for (final purchase in response.purchases) {
print(purchase?.subscriptionToken);
}
}, onError: (err) {
print("purchases err: $err" );
}
);

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

  • RuStorePaymentNetworkException — ошибка сетевого взаимодействия SDK;
  • RuStorePaymentCommonException — общая ошибка SDK;
  • RuStorePayClientAlreadyExist — ошибка повторной инициализации SDK;
  • RuStorePayClientNotCreated — попытка обратиться к публичным интерфейсам SDK до момента ее инициализации;
  • RuStorePayInvalidActivePurchase — запущен процесс оплаты неизвестного типа продукта;
  • RuStorePayInvalidConsoleAppId — не задан обязательный параметр console_app_id_value для инициализации SDK;
  • RuStorePaySignatureException — неверная сигнатура ответа (возникает при попытке совершить мошеннические действия);
  • EmptyPaymentTokenException — ошибка получения платежного токена;
  • RuStoreNotInstalledException — на устройстве пользователя не установлен RuStore;
  • RuStoreOutdatedException — версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;
  • RuStoreUserUnauthorizedException — пользователь не авторизован в RuStore;
  • RuStoreApplicationBannedException — приложение заблокировано в RuStore;
  • RuStoreUserBannedException — пользователь заблокирован в RuStore;
  • ProductPurchaseException — ошибка покупки продукта;
  • ProductPurchaseCancelled — произошла отмена покупки продукта (пользователь закрыл платежную шторку);
  • RuStoreException — базовая ошибка RuStore, от которой наследуются остальные ошибки.