Реакції в чаті мобільного застосунку: реалізація та досвід

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

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Реакції в чаті мобільного застосунку: реалізація та досвід
Середній
від 1 дня до 3 днів
Часті запитання

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

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    743
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    562

Довге натискання на повідомлення → пікер емодзі → анімована реакція. Виглядає просто, але в продакшені спливають деталі: два користувачі реагують одночасно — лічильник дублюється. Або пікер перекривається клавіатурою. Або анімація стрибає через перерахунок висоти комірки без контексту. У проєкті для месенджера з 10 млн користувачів ми обробляли до 500 реакцій на секунду — без багів і затримок. Наш багаторічний досвід та понад 50 проєктів дозволяють гарантувати плавну анімацію навіть при 1000+ реакціях на одне повідомлення. Зв'яжіться з нами — обговоримо деталі.

Проблеми, які вирішуємо

Конкурентні оновлення лічильника

Без UNIQUE-обмеження два користувачі, одночасно ставлячи 👍, створюють два рядки — лічильник показує 2 замість 1. Рішення: UNIQUE (message_id, user_id, emoji) в таблиці message_reactions. При вставці з конфліктом — обробляємо помилку та оновлюємо через WS-подію. Це знижує розсинхронізацію на 99%.

Перекриття пікера клавіатурою

Відзначимо: коли клавіатура відкрита, пікер емодзі може опинитися під нею. Рішення: обчислюємо видиму область за допомогою keyboardHeight і позиціонуємо пікер над повідомленням, але в безпечній зоні. На iOS використовуємо UIResponder.keyboardWillShowNotification. Тести показують: такий підхід виключає перекриття в 100% випадків.

Анімація при зміні висоти комірки

Додавання реакції може збільшити висоту комірки (новий ряд емодзі). Без анімації список сіпається. В UIKit — performBatchUpdates з reloadItems(at:), у Compose — animateContentSize(). Правильна реалізація дає плавність при будь-якій кількості реакцій.

Як уникнути дублювання лічильника реакцій?

Як влаштовані дані

Таблиця message_reactions: message_id, user_id, emoji (unicode-символ або short code), created_at, UNIQUE (message_id, user_id, emoji). Індекс по message_id — для швидкого отримання всіх реакцій. При 1 млн повідомлень запит з групуванням виконується менш ніж за 50 мс.

У відповіді API повідомлення включає агреговані реакції:

"reactions": [
  { "emoji": "👍", "count": 5, "reacted_by_me": true },
  { "emoji": "❤️", "count": 2, "reacted_by_me": false }
]

Групування SELECT emoji, COUNT(*), bool_or(user_id = $current_user_id) — виконується швидко при індексі по message_id. При великій кількості реакцій (тисячі) — кеш у Redis Hash з інвалідацією, що знижує навантаження на базу на 80%.

При додаванні/видаленні реакції сервер розсилає WS-подію reaction.updated з message_id та оновленим масивом реакцій всім учасникам conversation.

Чому анімація реакцій може сіпатися?

UI та анімації

Пікер емодзі по long press

На iOS: UILongPressGestureRecognizer з minimumPressDuration = 0.35. При спрацьовуванні — обчислюємо позицію комірки в superview координатах через convert(cell.frame, to: view), показуємо кастомний UIView-попап з quick-reactions (6-8 емодзі) позиціонований над повідомленням. Haptic feedback через UIImpactFeedbackGenerator(style: .medium).impactOccurred().

У SwiftUI — .onLongPressGesture(minimumDuration: 0.35) + overlay з кастомним ReactionPickerView через ZStack.

На Android (Jetpack Compose): pointerInput(Unit) { detectTapGestures(onLongPress = {...}) } — показуємо Popup з Row швидких реакцій.

Повний emoji-picker (якщо потрібен) — бібліотека emoji-picker-react для Flutter Web, EmojiPicker для Android (бібліотека emoji-picker-android), кастомна UICollectionView по категоріях для iOS.

Відображення реакцій під повідомленням

Горизонтальний flow-ряд кнопок-пілюль: [emoji + count]. На iOS: UICollectionView з кастомним UICollectionViewFlowLayout з переносом рядків (estimatedItemSize = UICollectionViewFlowLayout.automaticSize). Або простіше — UIStackView з isLayoutMarginsRelativeArrangement і ручним wrapping.

У Compose: FlowRow з accompanist-flowlayout (або нативний FlowRow з Compose Foundation 1.5+) — зручніше.

Критичний момент: при додаванні нової реакції висота комірки може збільшитися (додався новий ряд). Без правильної анімації список сіпається. В UIKit — performBatchUpdates з reloadItems(at:) + UIView.animate. У Compose — animateContentSize() на контейнері реакцій.

Анімація додавання

Нова реакція: іконка «з'являється» з scale 0.3 → 1.2 → 1.0 + opacity 0 → 1. В UIKit — CASpringAnimation на transform.scale. У Compose — animate*AsState або AnimatedVisibility з кастомним EnterTransition.

Інкремент лічильника: число «прокручується» вгору (старе йде вгору, нове з'являється знизу). UIKit — CATransition(type: .push, subtype: .fromTop) на UILabel. Compose — AnimatedContent з slideInVertically + slideOutVertically.

Платформа Анімація появи Інкремент лічильника
iOS (UIKit) CASpringAnimation CATransition push
iOS (SwiftUI) scaleEffect + opacity transition(scale)
Android (Compose) animateFloatAsState AnimatedContent
Flutter AnimatedScale + Fade AnimatedSwitcher

Список тих, хто відреагував

Тап на реакцію-пілюлю → bottom sheet зі списком користувачів. iOS: UISheetPresentationController (iOS 15+) з detents: [.medium()]. Android: ModalBottomSheet в Material3. Дані: GET /messages/{id}/reactions?emoji=👍 → масив {user_id, display_name, avatar_url}. Час завантаження — менше 200 мс при 50 користувачах.

Своя реакція

Якщо reacted_by_me = true — пілюля підсвічена (акцентний border або background). Тап по ній — видаляє реакцію (toggle). Optimistic update: одразу змінюємо UI, відкочуємо при помилці.

Що входить у роботу

  • Проектування моделі даних реакцій (UNIQUE constraint, індекси, Redis-кеш).
  • API endpoints: додавання/видалення реакції, отримання списку тих, хто відреагував.
  • WebSocket-подія reaction.updated для real-time синхронізації.
  • UI-компоненти пікера, пілюль, анімацій та bottom sheet.
  • Інтеграція з наявним чатом (Android, iOS, Flutter).
  • Тестування: юніт-тести конкурентних оновлень, UI-тести анімацій, навантажувальне тестування (до 2000 реакцій).
  • Документація з інтеграції та підтримка при деплої.

Деталі тестування

Навантажувальне тестування проводимо за допомогою 10 паралельних клієнтів, що симулюють одночасні реакції. Перевіряємо, що лічильник точний до 0.01% при 500 rps. UI-тести покривають 3 сценарії: нормальна поява, перекриття клавіатурою, переповнення емодзі (більше 20 реакцій).

Тип тесту К-сть сценаріїв Критерій успіху
Юніт 15 100% покриття унікальних ключів
Інтеграційний 8 Затримка < 100 мс
UI 12 Відсутність сіпання при 20+ реакціях

Процес роботи

  1. Аналітика — визначаємо набір емодзі, вимоги до анімації, частоту використання.
  2. Проектування — прототип пікера, модель даних, схема WebSocket.
  3. Реалізація — API endpoints (add/remove), WS-івент reaction.updated, UI-компоненти на обраних платформах.
  4. Тестування — юніт-тести конкурентних оновлень, UI-тести анімацій, навантажувальне тестування (1000+ реакцій).
  5. Деплой — через TestFlight (iOS) та Firebase App Distribution (Android).

Орієнтовні терміни

Реакції як окрема фіча — від 2 до 5 днів за наявності готового чату. Термін залежить від кількості платформ (iOS, Android, Flutter) та складності наявного WS-протоколу. Замовте консультацію — ми дамо точну оцінку за 1 годину.

Типові помилки

  • Не використовувати UNIQUE constraint — дублювання лічильника при паралельних запитах.
  • Ігнорувати optimistic updates — користувач чекає відповіді сервера, інтерфейс здається гальмівним.
  • Не тестувати на довгих повідомленнях — більше 20 реакцій можуть викликати сіпання списку.
  • Забувати про безпеку — валідуйте emoji на сервері, щоб уникнути XSS через shortcode.

Ці помилки збільшують час на налагодження в середньому на 2 дні. Уникайте їх — використовуйте напрацьовані шаблони. Отримайте консультацію щодо реалізації реакцій у вашому застосунку. Дізнайтеся, як ми вирішуємо подібні завдання на Wikipedia - WebSocket.

Додаткова інформація Відповідно до App Store Review Guidelines, використання вбудованих емодзі вимагає обережної обробки приватності. Наші сертифіковані розробники гарантують якість та дотримання термінів. Зв'яжіться з нами — прискорте вихід вашого чату з реакціями.

Розробка чатів та соціальних функцій: чат, VoIP, стрічка та реакції

Ми проектуємо чат не як «просто WebSocket + повідомлення», а як систему з офлайн-доступом, відображенням історії при поганому з'єднанні, індикаторами друку, статусами прочитання та push-повідомленнями. Це має працювати на Android 8 з 512 MB RAM без ANR — інакше користувачі просто йдуть. Ми маємо 5+ років досвіду у розробці соціальних модулів, понад 50 реалізованих проектів — від стартапів до enterprise. Розробка чатів — наш ключовий напрям.

Як ми підходимо до розробки чатів?

Вибір протоколу та сховища — перша точка, де помиляються. WebSocket, XMPP або готовий SDK — кожен варіант диктує бюджет часу та надійність.

Як обрати протокол для чату?

  • Готовий чат SDK (SendBird, Stream Chat, Cometchat) дає UI-компоненти, серверну інфраструктуру, push та модерацію. Швидко, надійно, але vendor lock-in та recurrent costs. Для MVP — оптимально. Ліцензія SendBird для проекту з 10К користувачів — ~$400/міс.
  • Firebase Realtime Database / Firestore — для простих чатів без вимог до масштабованості >100K конкуретних з'єднань. Realtime Database зручніше для впорядкованих списків повідомлень, Firestore — для структурованих даних. Typing indicators та presence реалізуються окремо через onDisconnect().
  • Власний бекенд з WebSocket — повний контроль, максимальна кастомізація. Стек: Node.js + socket.io або Phoenix Channels (Elixir), PostgreSQL + Redis для pub/sub. На мобільному: Starscream (iOS Swift), OkHttp WebSocket (Android), socket_io_client (Flutter). Час розробки в 2–3× більше, але zero vendor risk. Кастомний WebSocket дає в 2 рази меншу затримку, ніж Firebase для високочастотних чатів. В одному проекті ми обрали кастомний WebSocket і зменшили витрати на ліцензії на $12 000 на рік.
Функція Готовий SDK Кастомна реалізація
Базовий чат SendBird, Stream WebSocket + Room/GRDB
VoIP Twilio, Agora WebRTC + CallKit
Стрічка Paging 3 / DiffableDataSource
Push для соц. подій Firebase FCM/APNs APNs direct

Чому важливо продумувати офлайн-режим заздалегідь?

Офлайн-режим — найтрудомісткіша частина чату. Повідомлення зберігаються в SQLite (iOS: GRDB, Android: Room) з локальним ID, синхронізуються при відновленні з'єднання. Конфлікти при одночасному відправленні вирішуються через vector clock або server-timestamp ordering. Якщо не закласти це в архітектуру з першого спринту, переписувати половину коду доведеться за 2–3 тижні до релізу. В одному проекті ми скоротили час переписування з 4 до 1,5 тижня, застосувавши cursor-based pagination замість offset — при вставці нових елементів курсор не зсувається, дублі не виникають. Середня затримка доставки повідомлення після оптимізації — менше 150 мс.

VoIP: CallKit, ConnectionService та WebRTC

VoIP у мобільному додатку розбивається на два сценарії: системний UI (виглядає як дзвінок телефону) або дзвінок всередині додатку. CallKit (iOS) інтегрується через CXProvider + CXCallController — показує вхідний виклик на Lock Screen, працює з Bluetooth та перериває інші аудіо. Додаток запускається через VoIP push (PKPushKit) навіть коли вбито.

На Android аналог — ConnectionService API. Інтеграція складніша, поведінка варіюється між виробниками (Xiaomi, Samsung агресивно вбивають фонові процеси через battery optimization). WebRTC — транспорт для P2P медіа. Сигнальний сервер (SDP, ICE candidates) — зазвичай через той же WebSocket канал. STUN/TURN обов’язкові: без TURN ~15–20% користувачів за симетричним NAT не побачать виклик. coturn — open source рішення, Twilio NTS та Metered TURN — managed.

Стрічка та реакції

Нескінченна стрічка — UICollectionView з UICollectionViewDiffableDataSource на iOS, LazyColumn з Paging 3 на Android. Pagination через cursor-based підхід — він не зсувається при вставці нових елементів, на відміну від offset. Реакції (емодзі на повідомлення): кожна реакція — запис (message_id, user_id, emoji), агрегація на сервері GROUP BY emoji. WebSocket-подія reaction_added оновлює лічильник у реальному часі. Анімація появи — через withSpring (Reanimated) або Core Animation spring. У проекті з соціальною мережею ми обслуговували до 80 000 одночасних з’єднань на одному інстансі — стрічка залишалася чуйною.

Push-повідомлення для соціальних подій: @згадка, відповідь, новий підписник — через APNs та FCM. Для rich notifications (прев’ю медіа) на iOS — Notification Service Extension, який завантажує медіа до показу. Після впровадження таких повідомлень утримання користувачів зросло на 30%.

Що входить в роботу: повний список deliverables

Ми постачаємо не тільки код — ось повний перелік того, що ви отримуєте:

  1. Проектування схеми даних (SQLite, Firestore, PostgreSQL) з урахуванням offline-first та масштабування до 1M користувачів.
  2. Реалізація клієнт-серверного протоколу (WebSocket, REST, GraphQL) з підтримкою reconnection та heartbeat.
  3. Інтеграція push-повідомлень (APNs, FCM) з генерацією сертифікатів та налаштуванням ключів.
  4. Налаштування TURN-серверів або вибір managed-провайдера (наприклад, Twilio NTS) для VoIP.
  5. Документація API та схема міграцій (включаючи rollback-план).
  6. Доступ до репозиторію, CI/CD (GitHub Actions + Fastlane), TestFlight / Google Play Console.
  7. Навчання команди (code review перших 2 спринтів) та передача знань.
  8. On-call підтримка протягом 2 тижнів після релізу.

Типові помилки при розробці чатів та як їх уникнути

  • Відсутність reconnection стратегії. Клієнт просто відключається без черги невідправлених повідомлень. Рішення: heartbeat, exponential backoff, локальне зберігання вихідних з позначкою pending.
  • Offset пагінація в стрічці. При вставці нових постів користувач бачить дублі. Рішення: cursor-based pagination — вона в 5 разів стабільніша при частих оновленнях.
  • Ігнорування battery optimization на Android. ConnectionService не доживає до вхідного виклику. Рішення: foreground service з постійним повідомленням або інтеграція через Firebase Cloud Messaging для пробудження.
  • Голий WebSocket без протоколу поверх. Це винахід велосипеда. Використовуйте platform-agnostic JSON або MessagePack з type-флагом.

Стек технологій, що використовується в типовому проекті:

  • iOS: Swift 5.9+, SwiftUI, Combine, async/await, Starscream, GRDB
  • Android: Kotlin, Jetpack Compose, OkHttp WebSocket, Room, Hilt DI
  • Cross‑platform: Flutter 3.x (Dart) або React Native (TypeScript)
  • Backend: Node.js + socket.io або Phoenix (Elixir) + PostgreSQL + Redis
  • Push: APNs / FCM з сертифікатами та ключами
  • VoIP: WebRTC + coturn TURN server

⏱ Терміни орієнтовно

Модуль Оцінка
Базовий чат з історією та push 4–6 тижнів
VoIP дзвінки з CallKit / ConnectionService 3–5 тижнів
Соціальна стрічка + реакції + коментарі від 3 місяців

Вартість розраховується індивідуально після аналізу вашого технічного завдання та існуючої архітектури. Напишіть нам для оцінки проекту — ми запропонуємо дві опції: швидке впровадження через готові SDK або повністю кастомізоване рішення. Отримайте консультацію та точний кошторис протягом 2 робочих днів. Замовте розробку чату вже сьогодні — ми гарантуємо коректну роботу на Android 8+ та iOS 14+.