Любовь, платежи и профит: как романтическая игра внедрила новый Pay SDK от RuStore

от автора

В какой-то момент всё становится серьёзным — даже в приложениях про любовь. Команда Redspell, создатели игры Senses (интерактивные романтические истории), решили стать одними из первых, кто интегрировал новую платёжку от RuStore — Pay SDK. И встроили — с нуля, но в итоге с ростом метрик.

Вот честный рассказ о том, как ребята внедряли RuStore Pay SDK, что пошло не так, как с этим справились и какие результаты в итоге получили. Если вы тоже раздумываете, стоит ли связываться — читайте до конца. Там есть приятные цифры.

Зачем вообще этот Pay SDK

Если коротко: Pay SDK — это способ встроить в приложение платежи, которые работают быстро, выглядят нативно и не заставляют пользователя вводить свой email в 2025 году (серьёзно, хватит уже). Разработан специально в RuStore, адаптируется под вашу архитектуру и не требует танцев с дебагером в полнолуние.

Что внутри:

  • Простая интеграция без лишних зависимостей;

  • Одно- и двухстадийная оплата (на любой вкус);

  • Вся логика платежей — у вас под контролем;

  • VK ID  — всё быстро и удобно;

  • Работает даже если у пользователя нет RuStore.

И да, вскоре он станет достойной альтернативой BillingClient SDK. Но уже сейчас умеет больше:

  • Купоны, возвраты, список продуктов без авторизации;

  • И даже чеки в мессенджер или почту, если вы по олдскулу.

Как всё начиналось

Когда Senses появился в RuStore, перед Redspell встал вполне логичный вопрос: как получить максимальную выгоду от монетизации. Всё-таки 85% дохода с приложения — это внутриигровые покупки, а значит, платёжка должна быть быстрой, нативной и не раздражать пользователя (ну, и разработчика, конечно). 

И тут на горизонте — Pay SDK: всё ещё в beta, но уже с полноценной функциональностью, официальной поддержкой и гибкостью под разные сценарии. Раньше Redspell использовали сторонние веб-интерфейсы для монетизации — решение не самое удобное, не нативное и не всегда стабильное. Поэтому переход на Pay SDK стал логичным шагом: хотелось, чтобы весь процесс оплаты проходил прямо внутри приложения — быстро, аккуратно и под контролем.

Выбирая между BillingClient SDK и новым Pay SDK, команда Redspell сразу сделала ставку на второй вариант — он уже закрывал нужные задачи и, что важно, активно развивается RuStore.

В итоге ребята не растерялись — и пошли в пилот.

Технический квест на Unity

Платформа у Redspell — Unity. SDK нужно было аккуратно прикрутить, не развалив игру.

Вкратце, что было не так:

Вызовы Pay SDK встроили через стандартный Unity Purchase Module — без лома кода.

Код
class RuStoreModule: AbstractPurchasingModule {  public const string STORE_NAME = "RuStore"; private static RuStoreModule _instance; public static IPurchasingModule Instance() { _instance ??= new RuStoreModule(); return _instance; } public override void Configure() { RegisterStore(STORE_NAME,new RuStore()); } }  internal class RuStore : IStore {  private IStoreCallback _storeCallback; public void Initialize(IStoreCallback callback) { _storeCallback = callback;  bool isRuStoreInstalled = RuStorePayClient.Instance.IsRuStoreInstalled(); if (!isRuStoreInstalled) { _storeCallback.OnSetupFailed(InitializationFailureReason.PurchasingUnavailable, "RuStore is not installed"); return; } var settings = BlackMagicSettings.Instance;  RuStorePayClient.Instance.GetPurchaseAvailability( onFailure: (error) => { // Process error _storeCallback.OnSetupFailed(InitializationFailureReason.PurchasingUnavailable,$"{error.name}:{error.description}"); }, onSuccess: (response) => { if (response.isAvailable) { RuStorePayClient.Instance.GetPurchases(OnGetPurchasesFailure,onGetPurchasesSuccess); } else { var error = response.cause; _storeCallback.OnSetupFailed(InitializationFailureReason.PurchasingUnavailable, $"{error.name}:{error.description}"); } } ); }

Но не обошлось без затыков: нужно было переопределить стандартный Unity Activity, добавить Java-файл и всё это собрать на CI под Android.

Ещё и уведомления с этим не дружили — конфликтовали.

Код
#if UNITY_ANDROID // && !UNITY_EDITOR public class RuStorePostProcessor : IPostGenerateGradleAndroidProject { public int callbackOrder => 100; public void OnPostGenerateGradleAndroidProject(string path) { var gradleDir = path;  #if RUSTORE PatchAndroidManifest(gradleDir); GenerateJavaHandler(gradleDir); #else Debug.Log("RuStore disabled"); RemoveJavaHandler(gradleDir); #endif  }  #if RUSTORE  void PatchAndroidManifest(string gradleDir) { string manifestPath = Path.Combine( gradleDir, "src", "main", "AndroidManifest.xml"); var doc = XDocument.Load(manifestPath);  XNamespace androidNs = "http://schemas.android.com/apk/res/android"; var application = doc.Root.Element("application"); // e.g. add an <activity> or <meta-data> entry: var activity = new XElement("activity", new XAttribute(androidNs + "name", "games.extras.blackmagic.RuStoreDeeplinkActivity"), new XAttribute(androidNs + "exported", "true") );  activity.Add( new XElement("intent-filter", new XElement("action", new XAttribute(androidNs + "name", "android.intent.action.VIEW")), new XElement("category", new XAttribute(androidNs + "name", "android.intent.category.DEFAULT")), new XElement("category", new XAttribute(androidNs + "name", "android.intent.category.BROWSABLE")), new XElement("data", new XAttribute(androidNs + "scheme", "@string/rustore_PayClientSettings_deeplinkScheme")) ) ); application.Add(activity); .... } void GenerateJavaHandler(string gradleDir) { string javaDir = Path.Combine( gradleDir, "src", "main", "java", "games", "extras", "blackmagic"); Directory.CreateDirectory(javaDir); string javaFile = Path.Combine(javaDir, "RuStoreDeeplinkActivity.java");  string code = @" package games.extras.blackmagic;  import android.app.Activity; import android.os.Bundle; import android.content.Intent; import ru.rustore.unitysdk.payclient.RuStoreUnityPayClient; import com.unity3d.player.UnityPlayerActivity; import android.util.Log;   public class RuStoreDeeplinkActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { .....

Как выкрутились:

Сделали дополнительный Activity, который ловит Intent и запускает SDK. Код генерируется через Unity Post-Processor — только когда надо. Гибко, красиво, работает.

Что в итоге?

Через пару месяцев стало ясно: SDK живёт, платежи идут, пользователи довольны. А главное — метрики сказали «да»:

  • Процент платящих пользователей в RuStore более чем в 3 раза превышает аналогичный показатель на Google Play.

  • Прирост APRU (Average Revenue Per User, средняя выручка на одного пользователя) составил +207 % по сравнению с Google Play и +63 % по отношению к App Store.

  • ARPPU (Average revenue per paying user, средняя выручка на одного платящего пользователя) на 29 % выше, чем в Google Play.

  • RuStore демонстрирует самый высокий средний чек среди всех платформ, опережая App Store на 28,4 %.

  • Huawei-пользователи остались в игре — отсутствие GMS больше не препятствует стабильным платежам.

А вам зачем это знать?

Если вы тоже публикуетесь в RuStore и вам нужна платёжка, которая:

  • быстро ставится;

  • не ломает архитектуру;

  • дружит с VK ID;

  • и в целом работает как надо —

то Pay SDK — рабочий инструмент, с которым можно запускать монетизацию уже сейчас. Redspell интегрировал его без драмы, метрики пошли вверх, пользователи не убежали — разве что в очередной виртуальный роман с новым пиксельным красавчиком или красавицей.

Плюс, если что-то не клеится — команда поддержки действительно отвечает, а не «мы передали вашу заявку в параллельную вселенную». 

А ещё у нас есть телеграм-канал — подписывайтесь, там регулярно появляется всякое полезное (и местами весёлое) для разработчиков.


ссылка на оригинал статьи https://habr.com/ru/articles/919134/