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

2.2.1

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

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

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

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

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

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

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

Для подключения скачайте RuStore Billing SDK и импортируйте его в проект (Assets > Import Package > Custom Package). Зависимости подключаются автоматически с помощью External Dependency Manager (включен в SDK).

подсказка

Если вы используете операционную систему macOS, измените настройки утилиты архивации. В настройках Archive Utility снимите флажок Keep expanding if possible. В противном случае архив проекта будет скачан некорректно.

Также вы можете склонировать код с помощью Git.

Для корректной обработки зависимостей SDK установите следующие настройки.

  • Edit > Project Settings > Player Settings > Publishing Settings, включите Custom Main Gradle Template и Custom Gradle Properties Template.
  • Assets > External Dependencies Manager > Android Resolver > Settings, включите Use Jetifier, Patch mainTemplate.gradle, Patch gradleTemplate.properties.

После настройки обязательно сделать Assets > External Dependencies Manager > Android Resolver > Force Resolve.

Minimum API level должен быть установлен не ниже 24. Минификация приложения (ProGuard/R8) в данный момент не поддерживается, необходимо её отключить в настройках проекта (File > Build Settings > Player Settings > Publishing Settings > Minify).

Для корректной работы оплаты через сторонние приложения (СБП, SberPay и др.) необходимо правильно реализовать обработку deeplink. Укажите в AndroidManifest.xml intent-filter с scheme вашего проекта (см. ниже).

AndroidManifest.xml
<activity
android:name="ru.rustore.unitysdk.RuStoreUnityActivity" android:theme ="@style/UnityThemeSelector" android:exported ="true">
<intent-filter>

<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>

<action android:name="android.intent.action.VIEW"/>

<category android:name="android.intent.category.DEFAULT"/>

<category android:name="android.intent.category.BROWSABLE"/>

<data android:scheme="yourappscheme"/>
</intent-filter></activity>

Здесь: yourappscheme — схема вашего deeplink, её можно изменить на другую.

Далее расширьте класс UnityPlayerActivity и добавьте обработку входящего intent в onNewIntent.

package ru.rustore.unitysdk;import android.os.Bundle;import android.content.Intent;import ru.rustore.unitysdk.billingclient.RuStoreUnityBillingClient;import com.unity3d.player.UnityPlayerActivity;public class RuStoreUnityActivity extends UnityPlayerActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
if (savedInstanceState == null ) {
RuStoreUnityBillingClient.onNewIntent(getIntent());
}
}
@Override protected void onNewIntent(Intent intent) {
super .onNewIntent(intent);
RuStoreUnityBillingClient.onNewIntent(intent);
}}

Разместите Java-файл с кодом расширения UnityPlayerActivity в папке проекта Assets. Если у вас уже есть своё расширение UnityPlayerActivity, перенесите в него код функций onCreate и onNewIntent.

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

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

Выберите в меню редактора пункт Window > RuStoreSDK > Settings > Billing Client.

RuStoreBillingClient.Instance.Init();

Если требуется инициализация с другими настройками, есть возможность передать их непосредственно из кода.

var config =  new RuStoreBillingClientConfig() {
consoleApplicationId = "11111" ,
deeplinkPrefix = "yourappscheme" ,
allowNativeErrorHandling = true,
enableLogs = true
};
RuStoreBillingClient.Instance.Init(config);
  • consoleApplicationId — код приложения из консоли разработчика RuStore (пример: https://console.rustore.ru/apps/123456).
  • deeplinkPrefix — URL-адрес для использования deeplink. В качестве названия может быть использовано любое уникальное имя (пример: yourappscheme).
  • allowNativeErrorHandling — разрешить обработку ошибок в нативном SDK (см. подробнее в разделе Обработка ошибок).
  • enableLogs — включить ведение журнала событий.
примечание
Схема deeplink, передаваемая в deeplinkPrefix, должна совпадать со схемой, указанной в AndroidManifest.xml (подробнее см. Обработка deeplink).

Если вам нужно проверить факт инициализации библиотеки, используйте свойство RuStoreBillingClient.Instance.isInitialized — его значение true, если библиотека инициализирована, и false, если Init еще не был вызван.

var isInitialized = RuStoreBillingClient.Instance.IsIninialized;

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

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

Для проверки доступности платежей используйте метод CheckPurchasesAvailability. Если все указанные выше условия выполняются, возвращается FeatureAvailabilityResult.isAvailable == true. В противном случае возвращается FeatureAvailabilityResult.isAvailable == false, где FeatureAvailabilityResult.cause — это ошибка о невыполненном условии.

Все возможные ошибки RuStoreException описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure.

RuStoreBillingClient.Instance.CheckPurchasesAvailability( 
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
if (response.isAvailable) {
// Process purchases available
} else {
// Process purchases unavailable
}
});

Работа с SDK

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

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

RuStoreBillingClient.Instance.GetProducts(productIds,
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
});

string[] productIds — список идентификаторов продуктов.

Метод возвращает список продуктов List<Product>.

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

public class Product {
public enum ProductStatus {
ACTIVE,
INACTIVE
}
public enum ProductType {
NON_CONSUMABLE,
CONSUMABLE,
SUBSCRIPTION
}
public string productId;
public ProductType productType;
public ProductStatus productStatus;
public string priceLabel;
public int price;
public string currency;
public string language;
public string title;
public string description;
public string imageUrl;
public string promoImageUrl;
public ProductSubscription subscription;
}
  • productId — идентификатор продукта.
  • productType — тип продукта.
  • productStatus — статус продукта.
  • priceLable — отформатированная цена товара, включая валютный знак на языке language.
  • price — цена в минимальных единицах (в копейках).
  • currency — код валюты ISO 4217.
  • language — язык, указанный с помощью BCP 47 кодирования.
  • title — название продукта на языке language.
  • description — описание на языке language.
  • imageUrl — ссылка на картинку.
  • promoImageUrl — ссылка на промокартинку.
  • subscription — описание подписки, возвращается только для продуктов с типом subscription.

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

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

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

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

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

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

Тип/СтатусINVOICE_CREATEDCONFIRMEDPAID
CONSUMABLE++
NON-CONSUMABLE++
SUBSCRIPTION++
примечание

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

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

RuStoreBillingClient.Instance.GetPurchases(
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
});

Метод возвращает List<Purchase> response — список покупок.

Структура покупки

public class Purchase {
public enum PurchaseState
{
CREATED,
INVOICE_CREATED,
CONFIRMED,
PAID,
CANCELLED,
CONSUMED,
CLOSED
}
public string purchaseId;
public string productId;
public string description;
public string invoiceId;
public string language;
public DateTime purchaseTime;
public string orderId;
public string amountLabel;
public int amount;
public string currency;
public int quantity;
public PurchaseState purchaseState;
public string developerPayload;
public string subscriptionToken;
}
  • purchaseId — идентификатор покупки.
  • productId — идентификатор продукта.
  • description — описание на языке language.
  • invoiceId — идентификатор счёта.
  • language — язык, указанный с помощью BCP 47 кодирования.
  • purchaseTime — время покупки.
  • orderId — уникальный идентификатор оплаты, сформированный приложением (UUID).
  • amountLable — отформатированная цена покупки, включая валютный знак на языке language.
  • amount — цена в минимальных единицах валюты.
  • currency — код валюты ISO 4217.
  • quantity — количество продукта.
  • purchaseState — состояние покупки:
  • developerPayload — указанная разработчиком строка, содержащая дополнительную информацию о заказе.
  • subscriptionToken — токен для валидации покупки на сервере.

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

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

RuStore содержит продукты следующих типов.

  • SUBSCRIPTION — подписка (можно купить на период времени, например: подписка в стриминговом сервисе).
  • NON_CONSUMABLE — непотребляемый (можно купить один раз, например: отключение рекламы в приложении).
  • CONSUMABLE — потребляемый (можно купить много раз, например: кристаллы в приложении).

Подтверждения требуют только продукты типа CONSUMABLE, если они находятся в состоянии PurchaseState.PAID.

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

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

RuStoreBillingClient.Instance.ConfirmPurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
  • purchaseId — идентификатор покупки.

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

Для отмены покупки используйте метод DeletePurchase.

RuStoreBillingClient.Instance.DeletePurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
  • purchaseId — идентификатор покупки.
к сведению

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

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

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

  • RuStoreNotInstalledException — на устройстве пользователя не установлен RuStore;
  • RuStoreOutdatedException — версия RuStore, установленная на устройстве пользователя, не поддерживает платежи;
  • RuStoreUserUnauthorizedException — пользователь не авторизован в RuStore;
  • RuStoreRequestLimitReached — с момента последнего отображения процесса прошло слишком мало времени;
  • RuStoreReviewExists — этот пользователь уже оценил ваше приложение;
  • RuStoreInvalidReviewInfo — проблемы с ReviewInfo;
  • RuStoreException — базовая ошибка RuStore, от которой наследуются остальные ошибки.

Возникающие ошибки передаются в обработчик методов SDK onFailure.

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

public class RuStoreError {
public string name;
public string description;
}
  • name – имя ошибки.
  • description – описание ошибки.

Автоматическая обработка ошибок

При вызове метода PurchaseProduct ошибки обрабатываются автоматически.

Если при инициализации SDK был передан параметр allowNativeErrorHandling == true, при возникновении ошибки, кроме вызова соответствующего обработчика Failure, пользователю будет показан диалог с ошибкой.

public fun RuStoreException.resolveForBilling(context: Context)

Изменить это поведение после инициализации можно установкой свойства AllowNativeErrorHandling.

RuStoreBillingClient.Instance.AllowNativeErrorHandling = false ;

Сценарий подтверждения и отмены покупки

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

Метод отмены покупки (deletePurchase) необходимо использовать, если:

  • метод получения списка покупок (getPurchases) вернул покупку со статусом:

    • PurchaseState.CREATED;
    • PurchaseState.INVOICE_CREATED;
  • метод покупки (purchaseProduct) вернул:

    • PaymentResult.Cancelled;
    • PaymentResult.Failure.

Метод потребления продукта (confirmPurchase) необходимо использовать, если метод получения списка покупок (getPurchases) вернул покупку типа CONSUMABLE и со статусом PurchaseState.PAID.