Разработка ленты подписок (Following Feed) в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Разработка ленты подписок (Following Feed) в мобильном приложении
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    760
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    646
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1056
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    878
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    450

Разработка ленты подписок (Following Feed) в мобильном приложении

Лента подписок — технически самый сложный компонент социального приложения. Не потому что сложно написать SELECT posts WHERE author_id IN (following_ids) ORDER BY created_at DESC — это работает до ~10K пользователей. Проблема начинается когда нужно держать ленту актуальной в реальном времени, обрабатывать «знаменитостей» с миллионом подписчиков в feed, и отдавать первый экран быстро.

Fan-out vs Fan-in: выбор архитектуры

Два классических подхода к формированию ленты:

Fan-out on write (push) Fan-in on read (pull)
Принцип При публикации пишем в ленты всех подписчиков При запросе ленты собираем посты из подписок
Плюсы Чтение быстрое (готовая лента в Redis) Нет дублирования данных, проще для «звёзд»
Минусы Запись дорогая для популярных авторов Чтение медленнее, сложнее ранжирование
Когда До ~100K подписчиков у автора Авторы с миллионами фолловеров

Большинство приложений используют гибрид: fan-out для обычных пользователей, fan-in для «звёзд» (>50K подписчиков). Порог настраивается.

Для MVP — fan-in достаточно:

SELECT p.*, u.name, u.avatar_url
FROM posts p
JOIN follows f ON p.author_id = f.followee_id
JOIN users u ON p.author_id = u.id
WHERE f.follower_id = :user_id
  AND p.created_at < :cursor
ORDER BY p.created_at DESC
LIMIT 20;

Индексы: follows(follower_id), posts(author_id, created_at DESC).

Realtime-обновления

Три варианта:

Pull to refresh — пользователь тянет вниз, запрашиваем посты новее firstPost.created_at. Самый простой вариант, работает везде.

WebSocket/SSE — сервер пушит новые посты клиенту. При получении показываем баннер «N новых постов» вверху ленты (как Twitter). Клиент не вставляет их автоматически — только по тапу на баннер, иначе лента прыгает под пальцем.

Long polling — компромисс без WebSocket.

На iOS WebSocket — URLSessionWebSocketTask. На Android — OkHttp WebSocket. На Flutter — web_socket_channel.

Пагинация и cursor

Обязательно cursor-based, не OFFSET:

  • cursor = created_at последнего поста на текущей странице (ISO 8601 string)
  • Запрос: GET /feed?cursor=2024-11-15T10:30:00Z&limit=20
  • Ответ: { items: [...], next_cursor: "...", has_more: true }

При OFFSET на 100-й странице база вычитывает 2000 строк только чтобы пропустить. При большом числе подписок и постов — секунды ожидания.

Кэширование на клиенте

iOS — сохраняем первые 50-100 постов ленты в CoreData или Realm. При открытии приложения — мгновенно показываем кэш, одновременно запрашиваем новые посты. Когда новые посты пришли — тихо вставляем их в начало (или показываем баннер). NSFetchedResultsController + NSDiffableDataSourceSnapshot для плавного обновления без мерцания.

Android — Room + Paging 3 с RemoteMediator. Локальная база — источник истины, RemoteMediator подгружает данные из сети в Room, Paging 3 рендерит из Room.

Flutter — Hive или Isar для локального кэша, flutter_bloc для управления состоянием страниц.

Алгоритмическая лента

Хронологическая лента — базис. Если нужна алгоритмическая (ранжирование по engagment): хранить score за каждый пост, пересчитывать через воркер (BullMQ/Celery) при добавлении лайков/комментариев. Клиент запрашивает ленту с параметром sort=ranked. Для первого запуска — хронологическая, после набора данных — переключение на алгоритмическую. Обе ленты как отдельные вкладки (Reels vs Following у Instagram).

Скролл и производительность

UICollectionView с UICollectionViewCompositionalLayout и DiffableDataSource — золотой стандарт на iOS. Prefetch данных через UICollectionViewDataSourcePrefetching. Изображения — Kingfisher с кэшированием в памяти и на диске.

На Android LazyColumn (Compose) или RecyclerView с ConcatAdapter. Изображения — Coil с rememberAsyncImagePainter.

Главная причина дёрганой прокрутки — декодировка изображений на main thread. Kingfisher и Coil делают это в background по умолчанию. При кастомной загрузке изображений — DispatchQueue.global(qos: .userInitiated).async (iOS) или Dispatchers.IO (Android).

Этапы работы

Выбор архитектуры ленты (fan-in/fan-out/гибрид) под ожидаемую нагрузку → API с cursor-пагинацией → UI ленты с кэшем → realtime-обновления → нагрузочное тестирование (k6) на сценарий «1000 запросов ленты одновременно».

Сроки

Базовая лента с pull-to-refresh и пагинацией — 2-3 дня. С realtime WebSocket, кэшем, алгоритмическим ранжированием — 7-10 дней. Стоимость рассчитывается индивидуально.