Два пользователя одновременно редактируют список задач: один на iPhone, другой на Android. Данные быстро расходятся, конфликты накапливаются, и итоговое состояние непредсказуемо. REST API не обеспечивает real-time, а создание собственного WebSocket-сервера с CRDT требует месяцев разработки и отладки. Потери данных из-за конфликтов могут достигать 15% от всех изменений.
Мы используем Liveblocks — управляемую инфраструктуру для совместного редактирования. Она предоставляет готовый WebSocket-сервер, CRDT-хранилище (на базе Liveblocks Storage), presence, комментарии и нотификации через облачное API. В браузере интеграция занимает один день, в мобильном приложении на React Native — от недели. Это ускоряет выход на рынок в 3–6 раз по сравнению с самостоятельной реализацией. Экономия на инфраструктуре может быть значительной.
Что даёт Liveblocks из коробки?
- Storage — CRDT-хранилище на базе собственной реализации с
LiveObject, LiveList, LiveMap. Изменения реплицируются между клиентами за <100 мс в одном регионе.
- Presence — эфемерный стейт пользователя: позиция курсора, выделение, статус. Не персистируется, только онлайн.
- Yjs-интеграция — через
@liveblocks/yjs можно использовать Yjs документы совместно с веб-редакторами (Tiptap, Slate).
Согласно Wikipedia, CRDT гарантирует консистентность в распределённых системах.
Как подключить Liveblocks в React Native?
- Установите пакеты:
npm install @liveblocks/client @liveblocks/react
- Создайте клиент с помощью
createClient и настройте аутентификацию.
- Определите типы Presence и Storage для вашего приложения.
- Экспортируйте хуки через
createRoomContext.
- Оберните экран редактора в
RoomProvider.
import { createClient } from '@liveblocks/client';
import { createRoomContext } from '@liveblocks/react';
const client = createClient({
authEndpoint: '/api/liveblocks-auth',
// или publicApiKey для прототипов
});
type Presence = {
cursor: { x: number; y: number } | null;
selectedItemId: string | null;
};
type Storage = {
items: LiveList<{ id: string; text: string; done: boolean }>;
};
export const { RoomProvider, useMyPresence, useStorage, useMutation } =
createRoomContext<Presence, Storage>(client);
RoomProvider оборачивает экран-редактор. Внутри useStorage даёт иммутабельный снапшот, useMutation — транзакционные мутации.
Проблема в RN: @liveblocks/client использует fetch и WebSocket, которые есть, но EventSource (SSE для нотификаций) отсутствует без полифила. Установите react-native-event-source и глобальный полифил:
import EventSource from 'react-native-event-source';
global.EventSource = EventSource;
Получите консультацию по настройке клиента и полифилов — это сэкономит вам до 40% времени на интеграцию.
Что такое Presence в мобильном контексте?
В браузере presence — координаты мыши. В мобильном приложении — другие кейсы:
- Совместное редактирование списка задач: presence =
{ focusedItemId: string | null } — подсвечиваем редактируемый элемент.
- Совместная доска: presence =
{ x, y, tool: 'pen'|'eraser' } — показываем стилус.
- Документный редактор: presence =
{ selection: { anchor, focus } | null } — выделение текста.
Используйте useOthersConnectionIds и useOther для реактивных данных о присутствующих. Для оптимизации — useOthersMapped выбирает только нужные поля.
Почему стоит выбрать Liveblocks для мобильного приложения?
| Критерий |
Liveblocks |
Самостоятельная реализация |
| Время до продакшена |
2–8 недель |
3–6 месяцев |
| Поддержка офлайна |
Требует доработки |
Полный контроль |
| Стоимость инфраструктуры |
Подписка |
Значительные затраты |
| SLA |
99.9% (Pro) |
Зависит от вас |
| Data residency |
Только облако |
Полный контроль |
Сравнение показывает: Liveblocks выигрывает по скорости интеграции, но уступает в офлайн-режиме и контроле данных. Для большинства MVP и средних проектов этого достаточно.
Офлайн-режим: чего нет из коробки
Liveblocks не предоставляет офлайн-персистентность. При отсутствии сети изменения теряются. Мы решаем это буфером мутаций в AsyncStorage:
Пример реализации офлайн-буфера
const [pendingMutations, setPendingMutations] = useAtom(pendingMutationsAtom);
NetInfo.addEventListener(state => {
if (!state.isConnected) {
const snapshot = storage.toObject();
AsyncStorage.setItem('offline_snapshot', JSON.stringify(snapshot));
} else {
pendingMutations.forEach(mutation => mutation());
setPendingMutations([]);
}
});
Это не настоящий CRDT-офлайн — merge не гарантирован при одновременных изменениях офлайн. Для полного решения комбинируем с Yjs через @liveblocks/yjs и кастомным локальным провайдером. Сложнее, но правильнее.
| Стратегия офлайна |
Сложность |
Гарантия консистентности |
Время внедрения |
| Буфер мутаций |
Низкая |
Нет, возможна потеря |
1–2 недели |
| Локальная копия + merge |
Средняя |
Частичная (last-write-wins) |
2–4 недели |
| Yjs с локальным провайдером |
Высокая |
Полная CRDT |
4–8 недель |
AppState и реконнект
iOS убивает WebSocket при фоне. SDK переподключается автоматически, но room.getStatus() проходит через reconnecting. Если UI не реагирует, пользователь видит устаревший стейт. Обрабатывайте явно:
const status = useStatus();
if (status === 'reconnecting') {
return <ReconnectingBanner />;
}
Что входит в работу
- Настройка клиента Liveblocks и провайдера аутентификации.
- Интеграция Storage и Presence для вашего use-case.
- Реализация офлайн-буфера (опционально).
- Yjs-интеграция для совместимости с веб-редакторами.
- Тестирование реконнекта и обработки appState.
- Документация и обучение команды.
- Поддержка 2 недели после деплоя.
Закажите демо-проект с базовой интеграцией — мы покажем, как Liveblocks работает в вашем контексте. Свяжитесь с нами для оценки проекта за 1–2 рабочих дня.
Как мы оцениваем проект
Ориентировочные сроки:
- Базовая интеграция (Storage + Presence, без офлайна): 2–4 недели.
- С офлайн-буфером: 3–6 недель.
- С Yjs и полным офлайном: 6–10 недель.
Стоимость рассчитывается индивидуально после анализа вашего MVP. Получите консультацию — оценим проект за 1–2 рабочих дня.
Наш опыт: более 5 лет в мобильной разработке, 15+ проектов с real-time синхронизацией. Работаем с Liveblocks с момента его публичного релиза.
Интеграция API в мобильное приложение: с чего начать
Запрос уходит, ответ не приходит, timeout — 30 секунд. Пользователь смотрит на спиннер. Сети нет — мобильная карта в метро. Или сеть есть, но сервер вернул 200 с HTML-страницей ошибки вместо JSON — и приложение крашит при JSONDecoder.decode(). Мы видим такие кейсы на каждом втором проекте. Поэтому интеграция API в мобильное приложение — это не просто вызов endpoint'а, а проектирование надёжного сетевого слоя: обработка ошибок, кэширование, offline-режим, certificate pinning. Закажите аудит текущего сетевого слоя — оценим проект за 1 день.
Почему стандартные библиотеки недостаточны? URLSession и OkHttp предоставляют базовый HTTP-клиент, но для production нужны retry с exponential backoff, валидация статус-кодов, типизированная десериализация и мониторинг состояния сети. Без этого приложение теряет данные и пользователей. Мы уже 5 лет занимаемся мобильной разработкой и реализовали более 30 проектов с интеграцией API на iOS, Android и Flutter — от стартапов до enterprise-решений.
Как выбрать протокол для интеграции API?
| Протокол |
Размер ответа |
Скорость парсинга |
Кэширование |
Подходит для |
| REST |
большой (фиксированная структура) |
среднее |
HTTP-кеш + локальное |
CRUD, типовые экраны |
| GraphQL |
минимальный (только нужные поля) |
среднее (нормализованный кеш) |
in-memory кеш (Apollo) |
сложные UI с разными выборками |
| gRPC |
минимальный (protobuf) |
высокое |
на уровне стримов |
high-load, real-time, IoT |
| WebSocket |
— (бинарный/текст) |
— |
вручную |
чаты, котировки, синхронизация |
REST остаётся стандартом для большинства проектов. Но когда на экране профиля нужно 5 полей из 40, GraphQL исключает over-fetching и сокращает трафик на 30–60%. gRPC оправдан при тысячах запросов в минуту (trading, IoT) — бинарная сериализация в 3–5 раз быстрее JSON. WebSocket — единственный выбор для real-time без polling (сообщения, уведомления).
Пример из практики: для финтех-приложения мы заменили REST (40 полей) на GraphQL — размер ответа сократился с 12 КБ до 2,5 КБ, время рендера экрана упало на 70%. Экономия трафика составила около 15 000 ₽ в месяц при 100 000 активных пользователей.
Как обеспечить надёжность соединения и offline-first
Пользователи теряют сеть в метро, лифте, тоннеле. Мобильное приложение обязано работать без интернета — хотя бы в read-only режиме. Мы внедряем паттерн offline-first:
- При открытии экрана сначала показываем данные из локального кеша (Core Data / Room).
- Параллельно выполняем сетевой запрос, обновляем UI после ответа.
- Если сеть недоступна — показываем кешированные данные и метку «нет соединения».
- При восстановлении сети автоматически синхронизируем изменения.
Для кэширования HTTP-ответов используем URLCache (iOS) и OkHttp Cache (Android) с поддержкой Cache-Control. Для структурированных данных — SwiftData / Room. NWPathMonitor / ConnectivityManager.NetworkCallback отслеживают состояние сети и триггерят обновление.
REST и выбор клиентской библиотеки
Alamofire (iOS) — де-факто стандарт для Swift-проектов. Поверх URLSession добавляет request chaining, response validation, automatic retry, certificate pinning через ServerTrustManager. AF.request() с .validate() возвращает ошибку для любого статус-кода вне 200–299. Без .validate() Alamofire считает 404 и 500 успешными ответами. С Swift Concurrency — async-версия через serializingDecodable.
Retrofit (Android) — аннотационный HTTP-клиент поверх OkHttp. Интерфейс с аннотациями компилируется в реализацию. @GET, @POST, @Path, @Query, @Body — декларативное описание API. OkHttp под капотом: connection pooling, transparent gzip, HTTP/2 multiplex. HttpLoggingInterceptor — логирование в debug-сборке. Authenticator — автоматический refresh токена при 401.
Ktor (KMM/Flutter) — мультиплатформенный HTTP-клиент. На iOS работает через Darwin engine (URLSession), на Android — через OkHttp. Единый код для обеих платформ при KMM-архитектуре.
GraphQL: когда REST не справляется
REST возвращает фиксированную структуру. Экран профиля требует name, avatar, email — сервер отдаёт 40 полей. Over-fetching. GraphQL решает это: клиент запрашивает ровно нужные поля. Это критично для мобайла, где трафик и время парсинга — реальные ограничения. Apollo iOS и Apollo Kotlin генерируют типизированные классы по схеме: schema.graphql + query-файлы → строгие типы на этапе компиляции. Subscriptions через WebSocket — real-time без polling. Ограничение: GraphQL сложнее кешировать на уровне HTTP. Apollo использует нормализованный in-memory кеш InMemoryNormalizedCache — запросы с пересекающимися данными обновляют кеш без дублирования. Apollo GraphQL Documentation
WebSocket: real-time без лишнего трафика
Polling (setInterval каждые 5 секунд) — трата батареи и трафика. WebSocket — постоянное двунаправленное соединение. iOS: URLSessionWebSocketTask (нативный, iOS 13+). Android: OkHttp WebSocket. Обязательная обработка reconnect: при onFailure — экспоненциальный backoff (1с → 2с → 4с → 8с → максимум 60с). Socket.IO — надстройка с автоматическим reconnect, но для новых проектов предпочтительнее нативный WebSocket (меньше зависимостей).
gRPC: для высоконагруженных сервисов
gRPC с protobuf — бинарная сериализация: меньше размер, быстрее парсинг. grpc-swift для iOS, grpc-kotlin для Android. Protobuf-схема компилируется в типизированные классы. Streaming (server-side, client-side, bidirectional) — нативная возможность. Порог применения: высокая частота запросов (trading, IoT) или критичная latency. Для обычного CRUD REST проще в дебаге и мониторинге.
Certificate Pinning и безопасность
Корпоративный proxy может перехватить HTTPS через подмену сертификата. Certificate pinning предотвращает это: приложение принимает только конкретный сертификат или публичный ключ. Alamofire: ServerTrustManager с PinnedCertificatesTrustEvaluator. OkHttp: CertificatePinner с SHA-256 хешем. Операционная сложность: при ротации сертификата старые версии приложения перестают работать. Решение — pinning на публичный ключ CA или поддержка нескольких пинов с grace period. Подробнее о certificate pinning на Wikipedia
Что входит в работу
| Этап |
Длительность |
Результат |
| Анализ API и requirements |
1–2 дня |
Спецификация эндпоинтов, выбор протокола, схема кэширования |
| Реализация сетевого слоя |
3–5 дней |
Клиентская библиотека, обработка ошибок, retry, pinning |
| Offline-режим и кеширование |
2–3 дня |
Локальное хранилище, offline-first паттерн |
| Интеграция и тестирование |
2–3 дня |
Юнит-тесты (URLProtocol/OkHttp MockWebServer), UI-тесты |
| Деплой и документация |
1 день |
CI/CD, доступы к сторам, README для команды |
Мы передаём: исходный код сетевого слоя, документацию по используемым библиотекам, инструкцию по ротации сертификатов, поддержку в течение 2 недель после сдачи.
Сроки и стоимость
Реализация сетевого слоя с REST, retry, кэшированием и offline-режимом — 1–2 недели. Добавление GraphQL или WebSocket — ещё 1–2 недели. gRPC — 2–3 недели, включая кодогенерацию. Стоимость рассчитывается индивидуально после анализа API и требований к offline-поведению. Оценим проект за 1 день — свяжитесь для консультации.