Реализация 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 (онлайн-статус, активность) для collaboration в мобильном приложении

Presence — это эфемерный слой данных о том, что пользователь делает прямо сейчас: онлайн ли он, на каком экране, что редактирует, где его курсор. В отличие от обычных данных приложения, presence не нужно хранить в БД — оно живёт только пока активно соединение. Но реализовать его правильно сложнее, чем кажется.

Почему нельзя просто хранить is_online в Firestore

Классическая ошибка: добавить поле lastSeen в документ пользователя и обновлять его каждые 30 секунд. Проблемы:

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

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 как «был онлайн N минут назад»

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

Оценка

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