Мы разрабатываем систему виртуальной валюты (баллов и монет) для мобильных приложений с нуля или интегрируем в существующий проект. Баги в начислении монет — это либо пустые кошельки пользователей (злые отзывы, падение DAU на 20%), либо переполнение (убытки для бизнеса, иногда до 15% выручки). Наш опыт — 5+ лет в коммерческой мобильной разработке, 15+ проектов с геймификацией. За это время мы накопили паттерны для разных архитектур — от MVP до модульных монорепозиториев. Разработка под ключ — от проектирования ledger до деплоя в магазины.
Рост LTV на 25% после внедрения системы валюты — не редкость. Средний чек IAP consumable составляет $4.99, что при правильной настройке увеличивает ARPU. При этом без должной защиты от читерства можно потерять до 30% выручки из-за накруток. Наши решения проверены на проектах с миллионной аудиторией.
Оставьте заявку — мы подберём оптимальную архитектуру под ваш проект.
Транзакционность — основа
Каждая операция с балансом — это атомарная транзакция с debit/credit записью в ledger таблице, а не просто UPDATE balance = balance + N. Причина: без атомарности при одновременных запросах начисления и списания получаем некорректный баланс. Используем SELECT FOR UPDATE на сервере или оптимистичную блокировку (UPDATE balance WHERE balance = :expected).
Клиент при любой транзакции получает полный ответ:
{ "balance": 1250, "delta": 100, "transaction_id": "uuid", "reason": "daily_bonus" } Никогда не пересчитываем баланс на клиенте — только отображаем значение с сервера.
Как защитить систему валюты от читерства?
Отладочный прокси. Charles Proxy или mitmproxy позволяет пересылать запросы и изменять ответы. Если ответ /rewards/daily-bonus возвращает {"coins": 100} без подписи сервера — клиент может показать «получил 100 монет», но сервер в это время должен самостоятельно начислять и не доверять значению из ответа.
SSL Pinning. Базовая защита от MITM: TrustKit (iOS) / OkHttp CertificatePinner (Android). Не абсолютная защита — Frida или root + SSL Kill Switch обходят pinning. Но отсекает 90% script-kiddie попыток.
Rate limiting операций. Двойное нажатие кнопки «Собрать бонус» — debounce на клиенте (250ms throttle) плюс серверная защита через idempotency_key (UUID от клиента). Сервер игнорирует повторный запрос с тем же ключом в течение 60 секунд.
Подробнее о rate limiting
Мы используем токен бакета (bucket algorithm) с лимитом 5 запросов в секунду на пользователя для операций начисления. Idempotency-ключ хранится в Redis с TTL 120 секунд.UI: анимация начисления монет
Монеты «летят» к счётчику — стандартная анимация для reward. Реализация: частицы через CAEmitterLayer (iOS) или Jetpack Compose Canvas с кастомным анимированным Modifier. Несколько монет-иконок вылетают из источника (позиция кнопки/иконки события), летят по кривой Безье к виджету баланса, при каждом «попадании» счётчик инкрементируется на 1. Плавный нарастающий эффект через CAKeyframeAnimation с path.
Счётчик баланса при обновлении — number rolling animation: цифры прокручиваются сверху вниз как одометр. На iOS через UILabel с CATransition или кастомный AnimatedNumberView в SwiftUI. На Android — ValueAnimator с TextSwitcher. Анимация длится 1.5-2 секунды, чтобы пользователь заметил начисление.
| Тип анимации | iOS | Android |
|---|---|---|
| Полет монет | CAEmitterLayer + CAKeyframeAnimation | Canvas + ObjectAnimator |
| Счётчик-одометр | AnimatedNumberView (SwiftUI) | ValueAnimator + TextSwitcher |
Почему серверный ledger надёжнее клиентского?
| Аспект | Серверный ledger | Клиентский баланс |
|---|---|---|
| Атомарность | Гарантирована (транзакции БД) | Риск гонок |
| Безопасность | Под защитой серверной валидации | Легко модифицируется |
| Аудит | Полная история операций | Нет доверенного журнала |
Покупка монет через IAP
Consumable продукты в StoreKit 2: «100 монет за $0.99», «550 монет за $4.99» и т.д. Product.purchase() → Transaction.finish() после начисления серверного баланса — важный порядок: сначала зачисляем монеты через сервер (серверная валидация чека), потом завершаем транзакцию. Если завершить транзакцию до зачисления и приложение упадёт — пользователь заплатил, монеты не получил.
На Android: BillingClient.launchBillingFlow() → Purchase.getPurchaseState() == PURCHASED → серверная валидация через Google Play Developer API → BillingClient.consumeAsync() (consumable должен быть consumed, иначе недоступен для повторной покупки).
Pending transactions (отложенные покупки на Android через семейный Google Pay или банковское подтверждение) — обрабатываем через BillingClient.PurchasesUpdatedListener, ждём подтверждения до начисления монет.
Согласно рекомендациям Apple, серверная валидация обязательна для consumable продуктов.
Как настроить серверную валидацию IAP: пошагово
- Получить receipt (iOS) или purchase token (Android) на клиенте.
- Отправить на наш сервер (POST /validate-purchase).
- Сервер выполняет HTTP-запрос к Apple Verify Receipt или Google Play Developer API.
- При успешной валидации начисляем монеты в ledger и возвращаем подтверждение.
- Клиент завершает транзакцию (Transaction.finish() / consumeAsync()).
История транзакций
Пользователь хочет понять, куда ушли монеты. TransactionHistory — пагинированный список (cursor-pagination) с типами: earned_daily_bonus, earned_referral, spent_purchase, spent_unlock, purchased_iap. Фильтр по типу. Локальный кеш последних 50 операций в Core Data / Room для мгновенного отображения без сетевого запроса.
Что входит в реализацию
- Проектирование схемы ledger и защиты от читерства
- Разработка IAP (consumable) + серверная валидация
- UI баланса + анимации
- История транзакций
- QA (включает тест parallel requests, pending transactions)
- Документация по API и интеграции
- Поддержка после запуска (опционально)
Ориентиры по срокам
Полная реализация системы виртуальной валюты с IAP, анимациями и историей транзакций — 3–5 рабочих дней при готовом серверном API. Если включает проектирование серверного ledger — 1–2 недели. Стоимость рассчитывается индивидуально.
Получите консультацию — закажите оценку вашего проекта под ключ. Гарантируем прозрачность и опыт в каждом этапе.







