SDK Платежи in-app для Godot (версия 10.1.0)
RuStore позволяет интегрировать платежи в мобильное приложение.
-
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
-
Если вы переходите на Pay SDK с billingClient SDK, ознакомьтесь с инструкцией по переходу. Подробности о Pay SDK можно узнать тут.
Подготовка к работе
Библиотеки плагинов в репозитории собраны для Godot Engine 4.2.1. Если вы используете другую версию Godot Engine, выполните шаги раздела Пересборка плагина.
- Скопируйте проекты плагина и приложения-примера из официального репозитория RuStore на GitFlic.
- Скопируйте содержимое папки
godot_example/android/pluginsв папкуyour_project/android/plugins. - В пресете сборки Android в списке Плагины отметьте плагины Ru Store Godot Pay и Ru Store Godot Core.
- Для Godot 4.2.2 и младше, в файле
your_project/android/build/build.gradleдобавьте секциюresolutionStrategy:
android {
...
}
configurations.all {
resolutionStrategy {
force 'androidx.core:core:1.9.0'
force 'androidx.core:core-ktx:1.9.0'
force 'androidx.lifecycle:lifecycle-runtime:2.6.2'
force 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata-core:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-process:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2'
}
}
Инициализация SDK
Перед вызовом методов библиотеки необходимо выполнить её инициализацию. Сама инициализация происходит автоматически, но для работы SDK в вашем файле Manifest.xml необходимо прописать console_app_id_value и internal_config_key.
<!-- Initializing sdk -->
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
Оба значения должны располагаться внутри тега <application>. Также к тегу <application> добавьте аттрибут tools:replace="android:label".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.godot.game"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto" >
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<!-- Additional attribute tools:replace -->
<application
android:label="@string/godot_project_name_string"
tools:replace="android:label"
android:allowBackup="false"
android:icon="@mipmap/icon"
android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
<meta-data
android:name="org.godotengine.editor.version"
android:value="${godotEditorVersion}" />
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleInstancePerTask"
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Initializing sdk -->
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
</application>
</manifest>
console_app_id_value — идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/и/versions. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versionsID приложения —123456.

ApplicationId, указанный вbuild.gradle, должен совпадать сapplicationIdAPK-файла, который вы публиковали в RuStore Консоль.-
Подпись
keystoreдолжна совпадать с подписью, которой было подписано приложение, опубликованное в RuStore Консоль. Убедитесь, что используемыйbuildType(пр.debug) использует такую же подпись, что и опубликованное приложение (пр.release).
В целях безопасности, SDK устанавливает android:usesCleartextTraffic="false" по умолчанию, чтобы предотвратить передачу данных по незащищённому HTTP и защитить от атак типа "Man-in-the-Middle". Если ваше приложение требует использования HTTP, вы можете изменить этот атрибут на true, но делайте это на свой страх и риск, так как это увеличивает шанс перехвата и подмены данных. Мы рекомендуем разрешать незащищённый трафик только в исключительных случаях и для доверенных доменов, предпочитая HTTPS для всех сетевых взаимодействий.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Initializing sdk -->
<string name="rustore_PayClientSettings_consoleApplicationId" translatable="false">198332</string>
<string name="rustore_PayClientSettings_internalConfigKey" translatable="false">godot</string>
</resources>
Обработка deeplink
Deeplink в RuStore SDK платежей нужна для корректной работы со сторонними приложениями оплаты. Она помогает пользователям быстрее совершать покупки в стороннем приложении и возвращаться в ваше приложение.
Допускаются только символы в кодировке ASCII. Формат должен соответствовать спецификации RFC-3986.
Для настройки deeplink в вашем приложении выполните два основных шага:
1. Измените код игровой активити.
- Откройте файл
GodotApp.javaрасположенный по пути*your_project*/android/build/src/com/godot/game. - Переопределите методы
onCreateиonNewIntentдля обработки входящих intent'ов, используя приведённый ниже код.
package com.godot.game;
import android.content.Intent;
import android.os.Bundle;
import org.godotengine.godot.GodotActivity;
import ru.rustore.godot.pay.RuStoreGodotPay;
public class GodotApp extends GodotActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.GodotAppMainTheme);
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreGodotPay.proceedIntent(getIntent());
}
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
RuStoreGodotPay.proceedIntent(intent);
}
}
Параметры метода proceedIntent:
Intent intent— интент, содержащий данные о платежной операции.SdkTheme sdkTheme— цветовая тема платежной шторки. Доступны два вариантаLIGHTиDARK(светлая и темная тема соотвественно), по умолчаниюLIGHT(необязательный параметр).Long maxRetryTimeMs— максимальное время (в миллисекундах) для повторных попыток инициализации платёжного клиента, по умолчанию 5000 мс (необязательный параметр).
2. Обновите AndroidManifest.xml.
- В секцию
<application>...</application>поместите тегmeta-dataс указанием ссылки на вашуDeeplink Scheme. - Установите атрибут
launchModeигровой активити в значениеsingleTop. - Создайте
activity-aliasуказав в атрибутеtargetActivityкласс игровой активити. - Внутри
activity-aliasобъявитеintent-filterс указанием ссылки на вашуDeeplink Scheme.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.godot.game"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto" >
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<application
android:label="@string/godot_project_name_string"
tools:replace="android:label"
android:allowBackup="false"
android:icon="@mipmap/icon"
android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
<meta-data
android:name="org.godotengine.editor.version"
android:value="${godotEditorVersion}" />
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
<!-- 1. Deeplink scheme -->
<meta-data
android:name="sdk_pay_scheme_value"
android:value="@string/rustore_PayClientSettings_deeplinkScheme" />
<!-- 2. Game Activity launchMode="singleTop" -->
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleTop"
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 3. Аctivity-alias for Game Activity -->
<activity-alias
android:enabled="true"
android:exported="true"
android:name=".RuStoreDeeplink"
android:targetActivity=".GodotApp" >
<!-- 4. Deeplink 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="@string/rustore_PayClientSettings_deeplinkScheme" />
</intent-filter>
</activity-alias>
</application>
</manifest>
Значение deeplinkScheme должно располагаться в файле ресурсов, например: your_project/android/build/res/values/rustore_values.xml.
Не задавайте значение deeplinkScheme напрямую в манифесте.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Initializing sdk -->
<string name="rustore_PayClientSettings_consoleApplicationId" translatable="false">198332</string>
<string name="rustore_PayClientSettings_internalConfigKey" translatable="false">godot</string>
<!-- Deeplink scheme -->
<string name="rustore_PayClientSettings_deeplinkScheme" translatable="false">yourappscheme</string>
</resources>
Работа с SDK
Перед использованием всех методов плагина должен быть создан экземпляр объекта RuStoreGodotPayClient.
var _pay_client: RuStoreGodotPayClient = RuStoreGodotPayClient.get_instance()
Проверка доступности работы с платежами
Для проверки доступности платежей, вызовите метод get_purchase_availability. При его вызове проверяются следующие условия.
- У компании подключена монетизация через консоль разработчика RuStore.
- Приложение не должно быть заблокировано в RuStore.
- Пользователь не должен быть заблокирован в RuStore.
RuStorePayGetPurchaseAvailabilityResult.isAvailable == true.
В противном случае возвращается RuStorePayGetPurchaseAvailabilityResult.isAvailable == false и RuStorePayGetPurchaseAvailabilityResult.cause, где cause — это ошибка о невыполненном условии (возможные ошибки описаны в разделе Обработка ошибок).
Перед использованием метода необходимо единожды выполнить подписку на события:
on_get_purchases_availability_success;on_get_purchases_availability_failure.
func _ready():
# Инициализация _pay_client
_pay_client.on_get_purchase_availability_success.connect(_on_get_purchase_availability_success)
_pay_client.on_get_purchase_availability_failure.connect(_on_get_purchase_availability_failure)
func _on_get_purchase_availability_success(result: RuStorePayGetPurchaseAvailabilityResult):
pass
func _on_get_purchase_availability_failure(error: RuStoreError):
pass
_pay_client.get_purchase_availability()
Проверка статуса авторизации пользователя
Для проверки статуса авторизации пользователя, вызовите метод get_user_authorization_status. Результатом выполнения метода является значение перечисления ERuStorePayUserAuthorizationStatus.Item:
AUTHORIZED— пользователь авторизован в RuStore.UNAUTHORIZED— пользователь неавторизован в RuStore. Данное значение также вернется если у пользователя нет установленного МП RuStore на девайсе.
Перед использованием метода необходимо единожды выполнить подписку на события:
on_get_user_authorization_status_success;on_get_user_authorization_status_failure.
func _ready():
# Инициализация _pay_client
_pay_client.on_get_user_authorization_status_success.connect(_on_get_user_authorization_status_success)
_pay_client.on_get_user_authorization_status_failure.connect(_on_get_user_authorization_status_failure)
func _on_get_user_authorization_status_success(result: ERuStorePayUserAuthorizationStatus.Item):
pass
func _on_get_user_authorization_status_failure(error: RuStoreError):
pass
_pay_client.get_user_authorization_status()
Получение списка продуктов
Для получения продуктов, добавленных в ваше приложение через RuStore консоль, необходимо использовать метод get_products.
Перед использованием метода необходимо единожды выполнить подписку на события:
on_get_products_success;on_get_products_failure.
func _ready():
# Инициализация _pay_client
_pay_client.on_get_products_success.connect(_on_get_products_success)
_pay_client.on_get_products_failure.connect(_on_get_products_failure)
func _on_get_products_success(products: Array[RuStorePayProduct]):
pass
func _on_get_products_failure(error: RuStoreError):
pass
var PRODUCT_IDS: Array[RuStorePayProductId] = [
RuStorePayProductId.new("con_1"),
RuStorePayProductId.new("non_con_1"),
]
_pay_client.get_products(PRODUCT_IDS)
product_ids — список идентификаторов продуктов (задаются при создании продукта в консоли разработчика). Список продуктов имеет ограничение в размере 1000 элементов.
Где в RuStore Консоль отображаются идентификаторы продуктов?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Выберите Монетизация в меню слева.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров.

Метод возвращает список продуктов. Ниже представлена модель продукта.
class_name RuStorePayProduct extends RefCounted
var productId: RuStorePayProductId = null
var type: ERuStorePayProductType.Item = 0
var amountLabel: RuStorePayAmountLabel = null
var price: RuStorePayPrice = null
var currency: RuStorePayCurrency = null
var title: RuStorePayTitle = null
var description: RuStorePayDescription = null
var imageUrl: RuStorePayUrl = null
var subscriptionInfo: RuStorePaySubscriptionInfo = null
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).type— тип продукта.CONSUMABLE/NON-CONSUMABLE/SUBSCRIPTION(потребляемый/непотребляемый/подписка).amountLabel— отформатированная цена покупки, включая валютный знак.price— цена в минимальных единицах (в копейках).currency— код валюты ISO 4217.title— название продукта на языкеlanguage.description— описание на языкеlanguage.imageUrl— ссылка на картинку.subscriptionInfo— информация о подписке (будет неnull, если тип продуктаSUBSCRIPTION).
subscriptionInfo— информация о подписке (будет не null, если тип продуктаSUBSCRIPTION).
class_name RuStorePaySubscriptionInfo extends RefCounted
var periods: Array[RuStorePaySubscriptionPeriod]
periods— cписок периодов подписки.
class_name RuStorePaySubscriptionPeriod extends RefCounted
class RuStorePayTrialPeriod extends RuStorePaySubscriptionPeriod:
var duration: String
var currency: String
var price: int
class RuStorePayPromoPeriod extends RuStorePaySubscriptionPeriod:
var duration: String
var currency: String
var price: int
class RuStorePayMainPeriod extends RuStorePaySubscriptionPeriod:
var duration: String
var currency: String
var price: int
class RuStorePayGracePeriod extends RuStorePaySubscriptionPeriod:
var duration: String
class RuStorePayHoldPeriod extends RuStorePaySubscriptionPeriod:
var duration: String
duration— длительность периода в формате ISO 8601.currency— код валюты ISO 4217.price— Цена в минимальных единицах валюты.
Получение списка покупок
Для получения списка покупок пользователя используйте метод get_purchases.
Перед использованием методов необходимо единожды выполнить подпи ску на события:
on_get_purchases_success;on_get_purchases_failure.
func _ready:
# Инициализация _pay_client
_pay_client.on_get_purchases_success.connect(_on_get_purchases_success)
_pay_client.on_get_purchases_failure.connect(_on_get_purchases_failure)
func _on_get_purchases_success(purchases: Array[RuStorePayPurchase]):
pass
func _on_get_purchases_failure(error: RuStoreError):
pass
# Инициализация _pay_client
# Вызов без фильтра
_pay_client.get_purchases()
# Вызов с фильтром
var product_type = ERuStorePayProductType.Item.CONSUMABLE_PRODUCT
var purchase_status = ERuStorePayPurchaseStatusFilter.Item.CONFIRMED
_pay_client.get_purchases(product_type, purchase_status)
Вызов с фильтром позволяет фильтровать покупки по типу тов аров и статусу покупки:
product_type — типы товаров:
ERuStorePayProductType.Item.NON_CONSUMABLE_PRODUCT— непотребляемые товары.ERuStorePayProductType.Item.CONSUMABLE_PRODUCT— потребляемые товары.ERuStorePayProductType.Item.SUBSCRIPTION— подписки.
purchase_status — статусы покупок:
-
Для продуктов:
ERuStorePayPurchaseStatusFilter.Item.PAID— успешное холдирование средств, покупка ожидает подтверждения со стороны разработчика.ERuStorePayPurchaseStatusFilter.Item.CONFIRMED— покупка подтверждена, средства списаны.
-
Для подписок:
ERuStorePayPurchaseStatusFilter.Item.ACTIVE— подписка активна.ERuStorePayPurchaseStatusFilter.Item.PAUSED— подписка в Hold периоде (например, из-за недостатка средств на карте), продолжаются попытки списания в соответствии с настройками тарифа подписки.
По умолчанию фильтры выключены, если значения не заданы, метод вернёт все покупки пользователя в статусах PAID, CONFIRMED, ACTIVE и PAUSED, независимо от типа товара.