Реалізація Presence (онлайн-статус, активність) для collaboration у мобільному додатку

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

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

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

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

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Реалізація Presence (онлайн-статус, активність) для collaboration у мобільному додатку
Середній
~3-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

Реалізація Presence (online-статус, активність) для collaboration в мобільному додатку

Presence — це ephemeral шар даних про те, що користувач робить прямо зараз: online ли він, на якому екрані, що редагує, де його курсор. На відміну від звичайних даних додатка, presence не потрібно зберігати у БД — воно живе тільки поки активно з'єднання. Але реалізувати його правильно складніше, ніж кажется.

Чому не можна просто зберігати is_online у Firestore

Класична помилка: додати поле lastSeen у документ користувача та оновлювати його кожні 30 секунд. Проблеми:

  • Убийство батареї: постійні write-операції у фоні. Android 8+ обмежує фонові задачі, iOS убиває Background Fetch через кілька хвилин.
  • Некоректний статус при крешу: додаток упав — is_online: true залишиться до наступного обновлення.
  • Гонки при кількох пристроях: користувач online на телефоні і планшеті. Вийшов з планшета — обнулив статус, хоча телефон ще активний.

Firebase Realtime Database: правильна реалізація через onDisconnect

Firebase RTDB має вбудований механізм — onDisconnect(). Сервер виконує задану операцію автоматично при розриві з'єднання, навіть якщо клієнт просто втратив мережу:

import database from '@react-native-firebase/database';

const userStatusRef = database().ref(`/status/${userId}`);
const isOfflineData = { state: 'offline', lastChanged: database.ServerValue.TIMESTAMP };
const isOnlineData = { state: 'online', lastChanged: database.ServerValue.TIMESTAMP };

// Реєструємо дію на відключення ДО встановлення online
await userStatusRef.onDisconnect().set(isOfflineData);
await userStatusRef.set(isOnlineData);

database.ServerValue.TIMESTAMP — серверна мітка часу, не залежить від часового поясу пристрою. Важливо: onDisconnect реєструється до set(isOnlineData) — інакше race condition, при якому клієнт може відключитися між двома викликами.

Для підтримки кількох пристроїв — лічильник активних сесій замість булевого флага:

// Використовуємо транзакцію для атомарного increment
const sessionsRef = database().ref(`/sessions/${userId}`);
await sessionsRef.transaction(current => (current || 0) + 1);
await sessionsRef.onDisconnect().transaction(current => Math.max((current || 1) - 1, 0));

is_online = sessions > 0. Крах на одному пристрої зменшить лічильник через onDisconnect, не торкнеться інших сесій.

AppState: синхронізація з життєвим циклом iOS/Android

import { AppState, AppStateStatus } from 'react-native';

useEffect(() => {
  const subscription = AppState.addEventListener('change', (nextState: AppStateStatus) => {
    if (nextState === 'active') {
      userStatusRef.onDisconnect().set(isOfflineData);
      userStatusRef.set(isOnlineData);
    } else if (nextState === 'background' || nextState === 'inactive') {
      userStatusRef.set(isOfflineData);
      userStatusRef.onDisconnect().cancel(); // скасовуємо, вже зробили вручну
    }
  });
  return () => subscription.remove();
}, []);

На Android при background у вас є кілька секунд до того, як система заморозить JS-тред. userStatusRef.set() — асинхронна операція, не гарантована. onDisconnect() як fallback обов'язковий.

Типизований presence з додатковим контекстом

Окрім online/offline, часто потрібно знати, що саме робить користувач:

type PresenceState = {
  status: 'online' | 'idle' | 'offline';
  currentScreen: string | null;
  editingItemId: string | null;
  lastChanged: number;
};

idle — користувач відкрив додаток, але 5+ хвилин не дотикався екрана. Детектується через PanResponder або TouchableWithoutFeedback на кореневому компоненті з debounce-таймером.

Отображення: аватари з індикатором

До списку учасників з presence-даними додаємо кольоровий бейдж:

  • Зелений: status === 'online'
  • Жовтий: status === 'idle'
  • Сірий: status === 'offline', показуємо lastChanged як «був online N хвилин тому»

Нюанс: не оновлюйте lastChanged при кожній зміні presence — тільки при зміні status. Інакше список буде перерендериватися кожні кілька секунд для кожного активного користувача.

Оцінка

Firebase RTDB presence з підтримкою кількох пристроїв, idle-detection та UI-компонентом: 1–3 тижні. Custom WebSocket presence на власному бекенді: 2–4 тижні.