Реализация донатов/подарков во время прямой трансляции в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Реализация донатов/подарков во время прямой трансляции в мобильном приложении
Средний
~5 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Реализация донатов/подарков во время прямой трансляции в мобильном приложении

Донаты в стриме — это не просто платёж. Это real-time событие: пользователь отправил подарок → анимация прилетает поверх видео → зрители видят имя донатера в ленте → стример получает уведомление. Между нажатием кнопки и появлением анимации должно проходить меньше секунды. Это требует продуманной связки: платёжный процессор → бекенд → WebSocket → клиент.

Архитектура: три параллельных потока

Донат проходит через три независимых слоя одновременно:

  1. Платёжный поток — списание через Stripe/IAP/Google Play Billing с подтверждением
  2. Real-time поток — WebSocket-событие всем зрителям трансляции
  3. Лента донатов — обновление UI-счётчика и скролл-лога

Ошибка в одном потоке не должна блокировать остальные. Анимация подарка показывается после подтверждения платежа, не до.

Виртуальная валюта: почему не прямые платежи

Большинство стриминговых приложений используют виртуальную валюту (монеты, кристаллы) вместо прямых транзакций. Причины:

  • App Store и Google Play берут 30% с in-app покупок, но виртуальная валюта позволяет разделить покупку монет (IAP) и трату монет (серверная логика) — списание происходит на сервере, App Store не участвует
  • Пользователь покупает пачку монет через IAP, тратит в любой момент — асинхронно от платёжного флоу
  • Агрегация мелких доноров: отправить 5 рублей напрямую — дорого по комиссиям, отправить 5 монет из купленных ранее — дёшево
// Покупка монет через Google Play Billing
val productDetails = // загружены через BillingClient.queryProductDetailsAsync

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                .setProductDetails(productDetails)
                .build()
        )
    )
    .build()

billingClient.launchBillingFlow(activity, billingFlowParams)

Типы подарков: GiftItem объект

data class GiftItem(
    val id: String,
    val name: String,           // "Роза", "Ракета", "Корона"
    val coinCost: Int,          // стоимость в монетах
    val animationUrl: String,   // Lottie JSON или MP4
    val displayDurationMs: Long // сколько показывать анимацию
)

Анимации подарков — Lottie (JSON, ~50-200 KB) или короткие MP4 (~500 KB). Lottie предпочтительнее: масштабируется без артефактов, поддерживает прозрачность, не требует медиадекодера.

Real-time: WebSocket событие подарка

После списания монет на сервере (атомарная операция в транзакции БД) — публикуем событие в WebSocket-канал трансляции:

{
  "type": "gift",
  "streamId": "stream-abc123",
  "senderId": "user-456",
  "senderName": "Алексей",
  "senderAvatar": "https://cdn.example.com/avatars/456.jpg",
  "giftId": "gift-rocket",
  "giftName": "Ракета",
  "coinAmount": 50,
  "timestamp": "2024-06-15T14:30:01.234Z"
}

Сервер обязан проверить баланс монет до публикации. Никогда не доверяйте клиенту: клиент говорит «отправить ракету за 50 монет» → сервер проверяет баланс, списывает, затем публикует событие. Не наоборот.

Клиент: очередь анимаций

Одновременно несколько зрителей могут отправить подарки. Нельзя показывать все анимации параллельно — экран превратится в хаос. Нужна очередь:

class GiftAnimationQueue {
    private var queue: [GiftEvent] = []
    private var isPlaying = false

    func enqueue(_ event: GiftEvent) {
        queue.append(event)
        if !isPlaying { playNext() }
    }

    private func playNext() {
        guard !queue.isEmpty else { isPlaying = false; return }
        isPlaying = true
        let event = queue.removeFirst()

        showGiftAnimation(event) { [weak self] in
            // completion после окончания анимации
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                self?.playNext()
            }
        }
    }

    private func showGiftAnimation(_ event: GiftEvent, completion: @escaping () -> Void) {
        let animationView = LottieAnimationView(name: event.giftId)
        animationView.frame = overlayView.bounds
        overlayView.addSubview(animationView)

        animationView.play { _ in
            animationView.removeFromSuperview()
            completion()
        }
    }
}

На Android аналогичная очередь через Lottie AnimationView и LinkedList<GiftEvent> с Handler.

Лента донатов: RecyclerView с prepend

Новые донаты добавляются в начало списка, не в конец:

class DonationAdapter : RecyclerView.Adapter<DonationViewHolder>() {
    private val donations = mutableListOf<DonationItem>()

    fun prepend(donation: DonationItem) {
        donations.add(0, donation)
        notifyItemInserted(0)
        recyclerView.scrollToPosition(0)
    }
}

Обработка оффлайн-зрителей

Зрители могут переподключиться в середине трансляции. При переподключении не нужно воспроизводить все пропущенные анимации — показываем только лог донатов текстом и последние N событий.

Топ донатеров: агрегация в реальном времени

// Redis ZSET для топ донатеров трансляции
// ZINCRBY stream:{streamId}:donations {coinAmount} {userId}
// ZREVRANGE stream:{streamId}:donations 0 9 WITHSCORES — топ 10

Обновляется при каждом донате, рассылается всем зрителям раз в 5-10 секунд через отдельный WebSocket-канал.

Что входит в работу

  • Серверная логика списания монет (атомарная транзакция)
  • WebSocket-рассылка событий всем зрителям
  • Очередь анимаций подарков на клиенте (Lottie)
  • Лента донатов с prepend-логикой
  • Топ донатеров в реальном времени
  • Обработка reconnect и восстановления состояния

Сроки

5 дней. Серверная часть с WebSocket и биллингом монет — 2 дня. Клиентская часть с анимациями и лентой — 2 дня. Интеграция, тестирование, edge cases — 1 день. Стоимость рассчитывается индивидуально.