Интеграция
Быстрый старт
Section titled “Быстрый старт”using UnityEngine;using HyperstoneSdk;
public class MyGame : MonoBehaviour{ void Start() { // Подписываемся на изменения конфигурации — можно вызвать до Initialize Hyperstone.WatchConfig(OnConfigChanged);
// Инициализируем с использованием учетных данных из Консоли Hyperstone Hyperstone.Initialize("YOUR_APP_ID", "YOUR_APP_SECRET"); }
void OnConfigChanged(HyperstoneConfig config) { // Читаем оптимизированные значения, отправленные Hyperstone int lives = config.GetIntOrDefault("n_lives", 3); bool showAdsAfterDeath = config.GetBoolOrDefault("show_ads_after_death", true);
// Применяем к логике вашей игры GameManager.Instance.SetLives(lives); GameManager.Instance.SetAdsAfterDeath(showAdsAfterDeath); }
void OnDestroy() { Hyperstone.UnwatchConfig(OnConfigChanged); }}Вот и всё. Hyperstone автоматически будет:
- Получать оптимизированную конфигурацию, адаптированную для этого пользователя
- Передавать её в ваш callback
- Отслеживать метрики сессии (количество сессий, время вовлеченности, retention)
- Отправлять накопленные метрики на бэкенд Hyperstone
Инициализация
Section titled “Инициализация”Вызовите Hyperstone.Initialize() один раз при запуске вашего приложения (обычно в MonoBehaviour.Start() или в bootstrap-скрипте):
Hyperstone.Initialize("YOUR_APP_ID", "YOUR_APP_SECRET");| Параметр | Тип | Описание |
|---|---|---|
appId | string | Ваш Application ID из Консоли Hyperstone. |
appSecret | string | Ваш Application Secret из Консоли Hyperstone. |
logLevel | HyperstoneClient.LogLevel | (Опционально) Уровень детализации логов. По умолчанию: LogLevel.Info. |
Вы можете найти свой App ID и App Secret в Консоли Hyperstone.
Initialize должен быть вызван только один раз. Последующие вызовы будут игнорироваться с предупреждением в логах.
Конфигурация
Section titled “Конфигурация”Подписка на изменения конфигурации
Section titled “Подписка на изменения конфигурации”Используйте Hyperstone.WatchConfig(), чтобы получать обновления конфигурации. Вы можете подписаться в любой момент в вашем проекте — даже до вызова Initialize. Это особенно полезно для разделенных архитектур, где разные системы регистрируют свой интерес к конфигурации независимо.
// Подписываемся заранее — даже до InitializeHyperstone.WatchConfig(OnConfigChanged);
void OnConfigChanged(HyperstoneConfig config){ // Этот метод вызывается: // 1. Немедленно с кэшированной конфигурацией (если она существует) // 2. Снова, когда с сервера приходит свежая конфигурация}При подписке:
- Если конфигурация уже доступна (закэширована из предыдущей сессии или получена с сервера), ваш callback сработает немедленно с текущей конфигурацией.
- Когда с сервера будет получена свежая конфигурация, все зарегистрированные callback-функции сработают снова с новой конфигурацией.
Для отписки:
Hyperstone.UnwatchConfig(OnConfigChanged);Чтение значений конфигурации
Section titled “Чтение значений конфигурации”HyperstoneConfig предоставляет типизированные методы доступа с возможностью указания значения по умолчанию (fallback). Ключи конфигурации и их типы значений определяются вами в Консоли Hyperstone при настройке параметров оптимизации.
void OnConfigChanged(HyperstoneConfig config){ // Примитивы с безопасными значениями по умолчанию int lives = config.GetIntOrDefault("n_lives", 3); float speed = config.GetFloatOrDefault("player_speed", 5.0f); double ratio = config.GetDoubleOrDefault("reward_ratio", 1.5); long bigNum = config.GetLongOrDefault("score_cap", 1000000L); bool showAds = config.GetBoolOrDefault("show_ads_after_death", true); string theme = config.GetStringOrDefault("ui_theme", "dark");
// Паттерн TryGet (возвращает false, если ключ отсутствует или тип не совпадает) if (config.TryGetInt("bonus_level", out int bonus)) { // Используем bonus }}Для получения полного списка методов доступа обратитесь к API Reference.
Десериализация конфигурации в объект
Section titled “Десериализация конфигурации в объект”Если ваша конфигурация четко соответствует C#-классу, вы можете десериализовать её одним вызовом с помощью JsonUtility от Unity:
[Serializable]public class GameConfig{ public int n_lives; public bool show_ads_after_death; public float player_speed;}
void OnConfigChanged(HyperstoneConfig config){ GameConfig gameConfig = config.AsObject<GameConfig>(); // или обновить существующий экземпляр: // config.OverwriteObject(existingGameConfig);}Отслеживание событий
Section titled “Отслеживание событий”Hyperstone должен знать, что происходит в вашем приложении, чтобы оптимизировать конфигурацию. SDK предоставляет методы для отслеживания стандартных событий (реклама, внутриигровые покупки) и кастомных событий/метрик.
Автоматически собираемые данные
Section titled “Автоматически собираемые данные”Некоторые события и свойства отслеживаются SDK автоматически и не требуют написания кода.
Свойства устройства пользователя
- Версия SDK, версия Unity и платформа
- Bundle ID приложения и числовая версия
- Операционная система, модель устройства и тип устройства (Телефон/Планшет)
- Код языка и часовой пояс
- Флаг режима разработчика
Системные метрики
- Сессии и время — общее время вовлеченности (в минутах) и общее количество сессий. Новые сессии начинаются при запуске приложения или при возврате из паузы после тайм-аута.
- Retention и стрики — общее количество разных дней игры, непрерывные серии заходов (streaks) и отслеживание календарных дней.
- Агрегированный доход — общий общий доход, общий рекламный доход/запросы/показы/ошибки и агрегированные итоги IAP.
- Конверсии — события конверсии в платящего пользователя (первая покупка игрока).
События рекламы
Section titled “События рекламы”// Пользователь увидел рекламу — укажите доход для ILRDHyperstone.LogAdImpression( adPlatform: "admob", // Медиационная платформа (например, "admob", "ironsource", "max") adNetwork: "meta", // Рекламная сеть, которая показала рекламу adFormat: "rewarded", // Формат рекламы ("banner", "interstitial", "rewarded", "native") revenueUsd: 0.0032 // Оценочный доход в USD);
// Запрос рекламыHyperstone.LogAdRequest( adPlatform: "admob", adFormat: "interstitial");
// Ошибка загрузки/показа рекламыHyperstone.LogAdError( adPlatform: "admob", adNetwork: "meta", adFormat: "interstitial", failReason: "no_fill" // Опционально, по умолчанию "unknown");События внутриигровых покупок (IAP)
Section titled “События внутриигровых покупок (IAP)”Вы можете измерять доход от внутриигровых покупок с помощью метода LogIapTransactionSuccess. Вы должны вручную передать локализованную цену, чтобы правильно измерить сгенерированный доход:
// Успешная покупкаHyperstone.LogIapTransactionSuccess( productId: "gems_100", currency: "USD", price: 4.99 // Цена будет отслеживаться как IAP-доход для расчета LTV);
// Ошибка покупкиHyperstone.LogIapTransactionError( productId: "gems_100", failReason: "cancelled");SDK автоматически обнаруживает первую успешную покупку и сообщает о событии конверсии в плательщика. Последующий рекламный доход для платящих пользователей дополнительно отслеживается как отдельное измерение.
Кастомные события и метрики
Section titled “Кастомные события и метрики”Для отслеживания специфичных для приложения данных используйте кастомные события и метрики:
// Простое событие (считается со значением = 1)Hyperstone.LogCustomEvent("level_completed");
// Событие с лейблами для сегментацииHyperstone.LogCustomEvent("level_completed", new Label("difficulty", "hard"), new Label("world", "forest"));
// Числовая метрика (суммирует значение)Hyperstone.IncrementCustomMetric("coins_spent", 50);
// Числовая метрика с лейбламиHyperstone.IncrementCustomMetric("damage_dealt", 127.5f, new Label("weapon", "sword"), new Label("enemy_type", "boss"));Правила именования кастомных метрик:
- Только буквенно-цифровые символы, дефисы и подчеркивания (
[a-zA-Z0-9-_]) - Максимум 100 символов
Лейблы (Labels) прикрепляют метаданные с низкой кардинальностью к измерениям. Сервис Hyperstone использует лейблы для сегментации и агрегации данных. Хорошими кандидатами для лейблов являются такие вещи, как рекламные сети, уровни сложности или категории предметов, но не уникальные ID пользователей или временные метки.
Примеры ILRD (Impression-Level Revenue Data)
Section titled “Примеры ILRD (Impression-Level Revenue Data)”Данные о доходе на уровне показов (ILRD) критически важны для оптимизации рекламного дохода. Вот как интегрировать их с популярными платформами медиации.
using GoogleMobileAds.Api;
// При настройке rewarded ad:rewardedAd.OnAdPaid += (AdValue adValue) =>{ // AdMob сообщает стоимость в микроединицах (1,000,000 микро = 1 единица валюты) double revenueUsd = adValue.Value / 1_000_000.0;
Hyperstone.LogAdImpression( adPlatform: "admob", adNetwork: "admob", // AdMob как сеть, когда не используется медиация adFormat: "rewarded", revenueUsd: revenueUsd );};
// Для медиированных объявлений извлекайте название фактической рекламной сети из имени класса адаптера или информации об ответе:rewardedAd.OnAdPaid += (AdValue adValue) =>{ double revenueUsd = adValue.Value / 1_000_000.0;
var responseInfo = rewardedAd.GetResponseInfo(); var loadedAdapterName = responseInfo?.GetLoadedAdapterResponseInfo()?.AdSourceName ?? "unknown";
Hyperstone.LogAdImpression( adPlatform: "admob", adNetwork: loadedAdapterName, adFormat: "rewarded", revenueUsd: revenueUsd );};IronSource (LevelPlay)
Section titled “IronSource (LevelPlay)”using Unity.Services.LevelPlay;
// Подписываемся на событие данных о показахIronSourceEvents.onImpressionDataReadyEvent += OnImpressionDataReady;
void OnImpressionDataReady(IronSourceImpressionData impressionData){ if (impressionData.revenue.HasValue) { Hyperstone.LogAdImpression( adPlatform: "ironsource", adNetwork: impressionData.adNetwork ?? "unknown", adFormat: impressionData.adUnit ?? "unknown", revenueUsd: impressionData.revenue.Value ); }}Управление данными и утилиты
Section titled “Управление данными и утилиты”Очистка пользовательских данных
Section titled “Очистка пользовательских данных”Чтобы сбросить все локально сохраненные данные Hyperstone (например, при выходе пользователя из аккаунта или когда вам нужен «чистый лист»):
Hyperstone.ClearData();Это удаляет сохраненный UID, закэшированную конфигурацию, накопленные метрики, историю сессий и статус плательщика. Следующий вызов Initialize будет воспринимать этого пользователя как совершенно нового.
Логирование
Section titled “Логирование”Управляйте уровнем детализации логов SDK:
Hyperstone.LogLevel = HyperstoneClient.LogLevel.Debug; // Подробно — полезно при разработкеHyperstone.LogLevel = HyperstoneClient.LogLevel.Info; // По умолчанию — инициализация и ключевые событияHyperstone.LogLevel = HyperstoneClient.LogLevel.Warning; // Только предупреждения и ошибкиHyperstone.LogLevel = HyperstoneClient.LogLevel.Error; // Только ошибкиВы также можете передать уровень логов прямо при инициализации:
Hyperstone.Initialize("YOUR_APP_ID", "YOUR_APP_SECRET", HyperstoneClient.LogLevel.Debug);Все логи SDK начинаются с префикса [Hyperstone]: для удобной фильтрации в консоли Unity.
Как это работает
Section titled “Как это работает”Понимание внутренних механизмов SDK поможет вам использовать его эффективно и отлаживать проблемы интеграции.
Архитектура
Section titled “Архитектура”Статический класс Hyperstone является фасадом над синглтоном HyperstoneClient (MonoBehaviour). При первом обращении SDK создает игровой объект [Hyperstone], помеченный DontDestroyOnLoad, чтобы он сохранялся при смене сцен.
sequenceDiagram
participant App as Ваше приложение
participant SDK as Hyperstone SDK
participant Storage as PlayerPrefs
participant Server as Сервер Hyperstone
Note over App, Server: Инициализация и получение конфигурации
App->>SDK: Hyperstone.WatchConfig(callback)
App->>SDK: Hyperstone.Initialize(appId, appSecret)
SDK->>Storage: Загрузка закэшированного UID, конфигурации, метрик
Storage-->>SDK: Кэшированные данные (если есть)
SDK-->>App: callback(кэшированная конфигурация)
SDK->>Server: POST /v1/c {свойства пользователя}
Note right of SDK: Заголовки: xp-app-id, xp-app-secret, xp-uid
Server-->>SDK: Config JSON + UID
SDK->>Storage: Сохранение UID + конфигурации
SDK-->>App: callback(свежая конфигурация)
Note over App, Server: Отслеживание событий
App->>SDK: LogAdImpression / LogIap / IncrementCustomMetric
SDK->>SDK: Накопление в буфере метрик
SDK->>Storage: Сохранение буфера (защита от вылетов)
Note over SDK, Server: Отправка метрик (debounced, с кулдауном)
SDK->>Server: POST /v1/i {пакет метрик}
Note right of SDK: Заголовки: xp-app-id, xp-app-secret, xp-uid
alt Успех
Server-->>SDK: 200 OK
SDK->>Storage: Очистка отправленных метрик
else Ошибка
Server-->>SDK: Error
SDK->>SDK: Возврат метрик в буфер для повтора
end
Note over SDK, Server: Автоматически (без кода)
loop Каждые 15с, пока приложение активно
SDK->>SDK: Инкремент времени вовлеченности
end
SDK->>SDK: Отслеживание сессий, retention, стриков
Жизненный цикл
Section titled “Жизненный цикл”- Инициализация —
Hyperstone.Initialize()создает/находит синглтон, сохраняет ваши учетные данные, загружает изPlayerPrefsлюбые закэшированные конфигурации и метрики, и начинает запрос на получение конфигурации. - Получение конфигурации — SDK отправляет
POSTзапрос к Hyperstone API с устройствами и свойствами пользователя. Сервер отвечает оптимизированной конфигурацией и уникальным идентификатором пользователя (UID). Оба значения сохраняются локально. - Доставка конфигурации — Как только конфигурация приходит, все зарегистрированные
WatchConfigcallback-функции вызываются. Если закэшированная конфигурация существовала с предыдущей сессии, callback-функции срабатывают немедленно при подписке, а затем снова, когда приходит свежая конфигурация. - Сбор метрик — События (показы рекламы, покупки, кастомные метрики, сессии, время вовлеченности) накапливаются в буфере в памяти и периодически сохраняются в
PlayerPrefs. Это гарантирует, что данные не будут потеряны при вылете приложения. - Отправка метрик — SDK группирует метрики и отправляет их на бэкенд с окном дебаунса (0.5с) и периодом кулдауна (20с), чтобы не перегружать сервер. Если отправка не удалась, метрики возвращаются в буфер и будут отправлены при следующей возможности.
- Управление сессиями — SDK автоматически отслеживает сессии, определяя новую сессию при запуске приложения или при возврате из фоновой паузы длительностью более 30 секунд. Время вовлеченности измеряется 15-секундными интервалами. Retention отслеживается как в «мягких днях» (16+ часов между сессиями), так и по календарным дням.
Локальное хранение
Section titled “Локальное хранение”Все данные хранятся в Unity PlayerPrefs под ключами с пространством имен вашего App ID (например, xp-uid-{appId}, xp-config-{appId}). Это означает, что:
- Конфигурация и метрики сохраняются после перезапуска приложения
- Метрики, которые не удалось отправить, буферизуются и отправляются повторно
- Каждое приложение (App ID) имеет изолированное хранилище (актуально для мультитенентности)
Потокобезопасность
Section titled “Потокобезопасность”Все вызовы статического API Hyperstone потокобезопасны. Вы можете безопасно вызывать Hyperstone.Initialize(), Hyperstone.WatchConfig(), Hyperstone.LogAdImpression() и все остальные методы из любого потока — включая фоновые потоки, async-задачи или коллбэки системы Job System.
Под капотом статический фасад Hyperstone захватывает SynchronizationContext главного потока Unity при запуске (через [RuntimeInitializeOnLoadMethod]). Если вызов производится из не-главного потока, он автоматически перенаправляется в главный поток с помощью SynchronizationContext.Post(). Это гарантирует, что базовый HyperstoneClient (который использует корутины и Unity API) всегда работает в главном потоке, при этом вашему коду не нужно беспокоиться о принадлежности к потоку.
Продвинутое: Мультитенентность (Multi-Tenancy)
Section titled “Продвинутое: Мультитенентность (Multi-Tenancy)”Статический API Hyperstone управляет одним общим экземпляром клиента (паттерн синглтон). В большинстве приложений этого достаточно.
Однако, если вашему приложению нужно взаимодействовать с несколькими приложениями Hyperstone одновременно (например, платформа публикации, хостящая несколько тайтлов, или одно приложение с разными областями оптимизации), вы можете создавать и управлять экземплярами HyperstoneClient вручную:
using UnityEngine;using HyperstoneSdk;
public class MultiTenantExample : MonoBehaviour{ private HyperstoneClient _gameplayClient; private HyperstoneClient _monetizationClient;
void Start() { // Создаем отдельные экземпляры клиентов для разных областей приложения _gameplayClient = CreateClient("GameplayOptimizer"); _gameplayClient.Initialize("GAMEPLAY_APP_ID", "GAMEPLAY_APP_SECRET"); _gameplayClient.WatchConfig(OnGameplayConfigChanged);
_monetizationClient = CreateClient("MonetizationOptimizer"); _monetizationClient.Initialize("MONETIZATION_APP_ID", "MONETIZATION_APP_SECRET"); _monetizationClient.WatchConfig(OnMonetizationConfigChanged); }
private HyperstoneClient CreateClient(string name) { var go = new GameObject($"[Hyperstone - {name}]"); DontDestroyOnLoad(go); return go.AddComponent<HyperstoneClient>(); }
void OnGameplayConfigChanged(HyperstoneConfig config) { int lives = config.GetIntOrDefault("n_lives", 3); // ... }
void OnMonetizationConfigChanged(HyperstoneConfig config) { int adCooldown = config.GetIntOrDefault("ad_cooldown_seconds", 60); // ... }}