5.0.0
RuStore позволяет интегрировать платежи в мобильное приложение.
Пример реализации
Ознакомьтесь с приложением-примером чтобы узнать, как правильно интегрировать SDK отзывов и оценок.
Условия работы платежей
- Kotlin
- Java
- На устройстве пользователя установлена актуальная версия RuStore.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения включена возможность покупок в Консоли RuStore.
Сервис имеет некоторые ограничения на работу за пределами России.
- На устройстве пользователя установлена актуальная версия RuStore.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения включена возможность покупок в Консоли RuStore.
Сервис имеет некоторые ограничения на работу за пределами России.
Подготовка к работе
- Kotlin
- Java
Добавление репозитория
Подключите репозиторий, как показано в примере ниже.
repositories {
maven {
url = uri("https://artifactory-external.vkpartner.ru/artifactory/maven")
}
}
Подключение зависимости
Добавьте следующий код в свой конфигурационный файл для подключения зависимости.
dependencies {
implementation("ru.rustore.sdk:billingclient:5.0.0")
}
Добавление репозитория
Подключите репозиторий, как показано в примере ниже.
repositories {
maven {
url "https://artifactory-external.vkpartner.ru/artifactory/maven"
}
}
Подключение зависимости
Добавьте следующий код в свой конфигурационный файл для подключения зависимости.
dependencies {
implementation 'ru.rustore.sdk:billingclient:5.0.0'
}
Обработка deeplink
- Kotlin
- Java
Для корректной работы оплаты через сторонние приложения (СБП, SberPay и др.) необходимо правильно реализовать о бработку deeplink. Укажите в AndroidManifest.xml
intent-filter
с scheme
вашего проекта (см. ниже).
<activity
android:name=".YourBillingActivity">
<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
— схема вашего deeplink, её можно изменить на другую.
Эта схема должна совпадать со схемой deeplink, указываемой при инициализации библиотеки billing-клиента.
Далее в Activity
, в которую необходимо вернуться после совершения оплаты (ваша страница магазина), нужно добавить следующий код.
class YourBillingActivity: AppCompatActivity() {
// Previously created with RuStoreBillingClientFactory.create()
private val billingClient: RuStoreBillingClient = YourDependencyInjection.getBillingClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
billingClient.onNewIntent(intent)
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
billingClient.onNewIntent(intent)
}
}
Для восстановления состояния вашего приложения при возврате с deeplink добавьте в AndroidManifest.xml
android:launchMode="singleTask"
.
<activity
android:name=".YourBillingActivity"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
Для корректной работы оплаты через сторонние приложения (СБП, SberPay и др.) необходимо правильно реализовать обработку deeplink. Укажите в AndroidManifest.xml
intent-filter
с scheme
вашего проекта (см. ниже).
<activity
android:name=".YourBillingActivity">
<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
— схема вашего deeplink, её можно изменить на другую.
Эта схема должна совпадать со схемой deeplink, указываемой при инициализации библиотеки billing-клиента.
Далее в Activity
, в которую необходимо вернуться после совершения оплаты (ваша страница магазина), нужно добавить следующий код.
public class YourBillingActivityextends AppCompatActivity {
// Previously created with RuStoreBillingClientFactory.create();
RuStoreBillingClient billingClient = YourDependencyInjection.getBillingClient();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
billingClient.onNewIntent(getIntent());
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
billingClient.onNewIntent(intent);
}
}
Для восстановления состояния вашего приложения при возврате с deeplink добавьте в AndroidManifest.xml
android:launchMode="singleTask"
.
<activity
android:name=".YourBillingActivity"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
Инициализация
Перед вызовом методов библиотеки необходимо выполнить её инициализацию.
- Kotlin
- Java
Создайте RuStoreBillingClient
, используя RuStoreBillingClientFactory.create()
.
val billingClient: RuStoreBillingClient = RuStoreBillingClientFactory.create(
context = app,
consoleApplicationId = "111111",
deeplinkScheme = "yourappscheme",
// Опциональные параметры
themeProvider = null,
debugLogs = false,
externalPaymentLoggerFactory = null,
)
-
context
— контекст Android. Может быть любым, в реализации используетсяapplicationContext
. -
consoleApplicationId
— код приложения из консоли разработчика RuStore (пример:https://console.rustore.ru/apps/123456
).
ApplicationId
, указанный в build.gradle
, должен совпадать с applicationId
APK-файла, который вы публиковали в Консоли RuStore.
-
deeplinkScheme
— схема deeplink, необходимая для возврата в ваше приложение после оплаты через стороннее приложение (например, SberPay или СБП). SDK генерирует свой хост к данной схеме.
yourappscheme
, должна совпадать со схемой, указанной в AndroidManifest.xml
(подробнее см. Обработка deeplink).-
themeProvider
— инт ерфейс, который предоставляет темуBillingClientTheme
. Возможны 2 реализации темыBillingClientTheme
: светлая (Light
) и тёмная (Dark
).Необязательный интерфейс, по умолчанию применяться светлая тема. -
externalPaymentLoggerFactory
— интерфейс, который предоставляет доступ ко внешней системе ведения журнала событий. -
debugLogs
— флаг регулирующий ведение журнала событий (логи будут автоматически отключены для Release-сборок).
Подпись keystore
должна совпадать с подписью, которой было подписано приложение, опубликованное в Консоли RuStore. Убедитесь, что используемый buildType
(пр. debug
) использует такую же подпись, что и опубликованное приложение (пр. release
).
Создайте RuStoreBillingClient
, используя RuStoreBillingClientFactory.create()
.
final Context context = getContext();
final String consoleApplicationId = "111111";
final String deeplinkScheme = "yourappscheme";
// Опциональные параметры
final BillingClientThemeProvider themeProvider = null;
final boolean debugLogs = false;
final ExternalPaymentLoggerFactory externalPaymentLoggerFactory = null;
RuStoreBillingClient billingClient = RuStoreBillingClientFactory.INSTANCE.create(
context,
consoleApplicationId,
deeplinkScheme,
// Опциональные параметры
themeProvider,
debugLogs,
externalPaymentLoggerFactory
);
-
context
— контекст Android. Может быть любым, в реализации используетсяapplicationContext
. -
consoleApplicationId
— код приложения из консоли разработчика RuStore (пример:https://console.rustore.ru/apps/123456
).
ApplicationId
, указанный в build.gradle
, должен совпадать с applicationId
APK-файла, который вы публиковали в Консоли RuStore.
-
deeplinkScheme
— схема deeplink, необходимая для возврата в ваше приложение после оплаты через стороннее приложение (например, SberPay или СБП). SDK генерирует свой хост к данной схеме.
yourappscheme
, должна совпадать со схемой, указанной в AndroidManifest.xml
(подробнее см. Обработка deeplink).-
themeProvider
— интерфейс, который предоставляет темуBillingClientTheme
. Возможны 2 реализации темыBillingClientTheme
: светлая (Light
) и тёмная (Dark
).Необязательный интерфейс, по умолчанию применяться светлая тема. -
externalPaymentLoggerFactory
— интерфейс, который предоставляет доступ ко внешней системе ведения журнала событий. -
debugLogs
— флаг регулирующий ведение журнала событий (логи будут автоматически отключены для Release-сборок).
Подпись keystore
должна совпадать с подписью, которой было подписано приложение, опубликованное в Консоли RuStore. Убедитесь, что используемый buildType
(пр. debug
) использует такую же подпись, что и опубликованное приложение (пр. release
).
Как работают платежи
Проверка доступности работы с платежами
- Kotlin
- Java
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения включена возможность покупок в Консоли RuStore.
checkPurchasesAvailability
.
Если все указанные выше условия выполняются, возвращается FeatureAvailabilityResult.Available
.
В противном случае возвращается FeatureAvailabilityResult.Unavailable(val cause: RuStoreException)
, где cause
— это ошибка о невыполненном условии.
Все возможные ошибки RuStoreException
описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure
.
RuStoreBillingClient.checkPurchasesAvailability(context)
.addOnSuccessListener { result ->
when (result) {
FeatureAvailabilityResult.Available -> {
// Process purchases available
}
is FeatureAvailabilityResult.Unavailable -> {
// Process purchases unavailable
}
}
}.addOnFailureListener { throwable ->
// Process unknown error
}
context
— контекст Android.
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения включена возможность покупок в Консоли RuStore.
checkPurchasesAvailability
.
Если все указанные выше условия выполняются, возвращается FeatureAvailabilityResult.Available
.
В противном случае возвращается FeatureAvailabilityResult.Unavailable(val cause: RuStoreException)
, где cause
— это ошибка о невыполненном условии.
Все возможные ошибки RuStoreException
описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure
.
RuStoreBillingClientExtKt.checkPurchasesAvailability(RuStoreBillingClient.Companion, getContext())
.addOnSuccessListener(result -> {
if (result instanceof FeatureAvailabilityResult.Available) {
// Hanlde purchases available
} else {
RuStoreException exception = ((FeatureAvailabilityResult.Unavailable) result).getCause();
// Hanlde purchases unavailable
}
})
.addOnFailureListener(error -> {
// Handle error
});
Работа с SDK
Получение списка продуктов
- Kotlin
- Java
getProducts
.
val productsUseCase: ProductsUseCase = billingClient.products
productsUseCase.getProducts(productIds = listOf("id1", "id2"))
.addOnSuccessListener { products: List<Product> ->
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
productIds
— список идентификаторов продуктов. Максимальная длина — 2083 символа в списке.
Метод возвращает
data class Product(
val productId: String,
val productType: ProductType?,
val productStatus: ProductStatus,
val priceLabel: String?,
val price: Int?,
val currency: String?,
val language: String?,
val title: String?,
val description: String?,
val imageUrl: Uri?,
val promoImageUrl: Uri?,
val subscription: ProductSubscription?,
)
Структура продукта
productId
— идентификатор продукта.productType
— тип продукта.productStatus
— статус продукта.priceLable
— отформатированная цена товара, включая валютный знак на языкеlanguage
.price
— цена в минимальных единицах (в копейках).currency
— код валюты ISO 4217.language
— язык, указанный с помощью BCP 47 кодирования.title
— название продукта на языкеlanguage
.description
— описание на языкеlanguage
.imageUrl
— ссылка на картинку.promoImageUrl
— ссылка на промокартинку.subscription
— описание подписки, возвращается только для продуктов с типомsubscription
.
Структура подписки
data class ProductSubscription(
val subscriptionPeriod: SubscriptionPeriod?,
val freeTrialPeriod: SubscriptionPeriod?,
val gracePeriod: SubscriptionPeriod?,
val introductoryPrice: String?,
val introductoryPriceAmount: String?,
val introductoryPricePeriod: SubscriptionPeriod?
)
subscriptionPeriod
— период подписки.freeTrialPeriod
— пробный период подписки.gracePeriod
— льготный период подписки.introductoryPrice
— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language
.introductoryPriceAmount
— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod
— расчётный период вступительной цены.
Структура периода подписки
data class SubscriptionPeriod(
val years: Int,
val months: Int,
val days: Int,
)
years
— количество лет.months
— количество месяцев.days
— количество дней.
Для получения списка продуктов используйте метод getProducts
.
ProductsUseCase productsUseCase = billingClient.getProducts();
productsUseCase.getProducts(Arrays.asList("id1", "id2"))
.addOnSuccessListener(products -> {
// Process success
}).addOnFailureListener(throwable ->
// Process error
);
productIds: List<String>
— список идентификаторов продуктов.
Структура продукта
public Product(
String productId,
@Nullable
ProductType productType,
ProductStatus productStatus,
@Nullable
String priceLabel,
@Nullable
Integer price,
@Nullable
String currency,
@Nullable
String language,
@Nullable
String title,
@Nullable
String description,
@Nullable
Uri imageUrl,
@Nullable
Uri promoImageUrl,
@Nullable
ProductSubscription subscription
) {
this.productId = productId;
this.productType = productType;
this.productStatus = productStatus;
this.priceLabel = priceLabel;
this.price = price;
this.currency = currency;
this.language = language;
this.title = title;
this.description = description;
this.imageUrl = imageUrl;
this.promoImageUrl = promoImageUrl;
this.subscription = subscription;
}
productId
— идентификатор продукта.productType
— тип продукта.productStatus
— статус продукта.priceLabel
— отформатированная цена товара, включая валютный знак на языкеlanguage
.price
— цена в минимальных единицах (в копейках).currency
— код валюты ISO 4217.language
— язык, указанный с помощью BCP 47 кодирования.title
— название продукта на языкеlanguage
.description
— описание на языкеlanguage
.imageUrl
— ссылка на картинку.promoimageurl
— ссылка на промокартинку.subscription
— описание подписки, возвращается только для продуктов с типомsubscription
.
Структура подписки
public ProductSubscription(
@Nullable
SubscriptionPeriod subscriptionPeriod,
@Nullable
SubscriptionPeriod freeTrialPeriod,
@Nullable
SubscriptionPeriod gracePeriod,
@Nullable
String introductoryPrice,
@Nullable
String introductoryPriceAmount,
@Nullable
SubscriptionPeriod introductoryPricePeriod
) {
this.subscriptionPeriod = subscriptionPeriod;
this.freeTrialPeriod = freeTrialPeriod;
this.gracePeriod = gracePeriod;
this.introductoryPrice = introductoryPrice;
this.introductoryPriceAmount = introductoryPriceAmount;
this.introductoryPricePeriod = introductoryPricePeriod;
}
subscriptionPeriod
— период подписки.freeTrialPeriod
— пробный период подписки.gracePeriod
— льготный период подписки.introductoryPrice
— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language
.introductoryPriceAmount
— вступительная цена в минимальных единицах валюты ( в копейках).introductoryPricePeriod
— расчётный период вступительной цены.
Структура периода подписки
public SubscriptionPeriod(
int years,
int months,
int days
) {
this.years = years;
this.months = months;
this.days = days;
}
years
— количество лет.months
— количество месяцев.days
— количество дней.
Покупка продукта
- Kotlin
- Java
Для вызова покупки продукта используйте метод purchaseProduct
.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.purchaseProduct(
productId = productId,
orderId = UUID.randomUUID().toString(),
quantity = 1,
developerPayload = null,
).addOnSuccessListener { paymentResult: PaymentResult ->
when (paymentResult) {
// Process PaymentResult
}
}.addOnFailureListener { throwable: Throwable ->
// Process error
}
productId: String
— идентификатор продукта.orderId: String
— уникальный идентификатор оплаты, сформированный приложением (UUID).quantity: Int
— количество продукта.developerPayload
— указанная разработчиком строка, содержащая дополнительную информацию о заказе.
Структура результата покупки
public sealed interface PaymentResult {
public data class Success(
val orderId: String?,
val purchaseId: String,
val productId: String,
val invoiceId: String,
val subscriptionToken: String? = null,
) : PaymentResult
public data class Cancelled(
val purchaseId: String,
) : PaymentResult
public data class Failure(
val purchaseId: String?,
val invoiceId: String?,
val orderId: String?,
val quantity: Int?,
val productId: String?,
val errorCode: Int?,
) : PaymentResult
public object InvalidPaymentState : PaymentResult()
}
Success
- результат успешного завершения покупки цифрового товара.Failure
- при отправке запроса на оплату или получения ста туса оплаты возникла проблема, невозможно установить статус покупки.Cancelled
— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.InvalidPaymentState
— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.
Для вызова покупки продукта используйте метод purchaseProduct
.
purchasesUseCase.purchaseProduct(productId, null, 1, developerPayload)
.addOnSuccessListener( result ->
// Process PaymentResult
)
.addOnFailureListener(throwable ->
// Process error
);
productId: String
— идентификатор продукта.orderId: String
— уникальный идентификатор оплаты, сформированный приложением (UUID).quantity: Int
— количество продукта.developerPayload
— указанная разработчиком строка, содержащая дополнительную информацию о заказе.
Структура результата покупки
public interface PaymentResult {
class Success implements PaymentResult {
@Nullable
String orderId;
String purchaseId;
String productId;
String invoiceId;
@Nullable
String subscriptionToken;
public Success(@Nullable String orderId, String purchaseId, String productId, String invoiceId,
@Nullable String subscriptionToken) {
this.orderId = orderId;
this.purchaseId = purchaseId;
this.productId = productId;
this.invoiceId = invoiceId;
this.subscriptionToken = subscriptionToken;
}
}
class Failure implements PaymentResult {
@Nullable
String purchaseId;
@Nullable
String invoiceId;
@Nullable
String orderId;
@Nullable
Integer quantity;
@Nullable
String productId;
@Nullable
Integer errorCode;
public Failure(@Nullable String purchaseId, @Nullable String invoiceId, @Nullable String orderId,
@Nullable Integer quantity, @Nullable String productId, @Nullable Integer errorCode) {
this.purchaseId = purchaseId;
this.invoiceId = invoiceId;
this.orderId = orderId;
this.quantity = quantity;
this.productId = productId;
this.errorCode = errorCode;
}
}
class Cancelled implements PaymentResult {
String purchaseId;
public Cancelled(String purchaseId) {
this.purchaseId = purchaseId;
}
}
class InvalidPaymentState implements PaymentResult {}
}
Success
- результат успешного завершения покупки цифрового товара.Failure
- при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.Cancelled
— запрос на покупку отправлен, при этом пользователь закрыл «платёжную шторку» на своём устройстве, и результат оплаты неизвестен.InvalidPaymentState
— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.