Реалізація спільного редагування документа в реальному часі в мобільному додатку
Спільне редагування тексту в реальному часі — одна з технічно складних задач у мобільній розробці. Не тому що алгоритми самі по собі складні, а тому що мобільне середовище додає кілька вимірів: нестабільна мережа, фоновий режим, нативна клавіатура з composition events, користувачі з затримкою 300ms+ через поганий сигнал.
Вибір алгоритму синхронізації
Два практичні підходи: Operational Transform (OT) та CRDT (Conflict-free Replicated Data Type).
OT — перевірено у Google Docs, Apache Wave. Операції (insert/delete з позицією) трансформуються на сервері з урахуванням конкурентних змін. Сервер — координатор, всі операції проходять через нього. Перевага: єдина історія операцій, конфліктів по визначенню нема. Недолік: сервер обов'язковий, offline-робота вимагає буферизації з подальшим merge.
CRDT — алгоритми як Automerge, Y.js, RGA (Replicated Growable Array). Немає центрального координатора, merge працює локально. Ідеальні для offline-first сценаріїв, де користувач редагує документ без мережі й синхронізується пізніше. Y.js — стандарт де-факто для вебу й React Native.
Для мобільного корпоративного редактора (Google Docs-подібний) — OT через WebSocket з сервером-координатором. Для коллаборативного блокнота з offline-режимом — Y.js + WebRTC або Y.js + WebSocket з провайдером синхронізації.
Y.js у React Native: реальна інтеграція
yjs — чистий JavaScript, працює у React Native без модифікацій. y-websocket — провайдер синхронізації через WebSocket. Типічна схема:
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';
const ydoc = new Y.Doc();
const provider = new WebsocketProvider('wss://your-server.com/sync', 'doc-room-id', ydoc);
const ytext = ydoc.getText('document');
YText — CRDT-тип для тексту з підтримкою форматування (bold, italic, headers). Інтегрується з Quill.js, ProseMirror, Slate.js на вебе. У React Native — через react-native-webview з Quill всередину, або нативний текстовий редактор з ручною синхронізацією через Y.js операції.
Другий варіант складніший, але дає нативний UX. Кастомний TextInput у React Native не підтримує beforeInput events — потрібен NativeEventEmitter і перехоп нативних keyboard events. На iOS — UITextViewDelegate, на Android — InputFilter або TextWatcher.
Курсори та awareness
Y.js Awareness Protocol — легковесний механізм розповсюджування ephemeral-даних (курсори, присутність, виділення тексту) між учасниками. Не зберігається в документі, не впливає на CRDT-історію.
provider.awareness.setLocalState({
user: { name: 'Іван', color: '#3B82F6' },
cursor: { anchor: 45, focus: 45 }
});
provider.awareness.on('change', () => {
const states = Array.from(provider.awareness.getStates().values());
// оновлюємо позиції курсорів інших користувачів
});
Відображення чужих курсорів у нативному TextInput — нетривіально. Потрібно вичислювати CGRect для позиції курсора через UITextView.caretRect(for:) на iOS та Layout.getDesiredWidth() / getLineTop() на Android. Позиція в символах → координати в пікселях — різні API на кожній платформі.
Конфлікти форматування та розв'язання
Y.js YText форматування працює через Delta-подібні операції з атрибутами. Конкурентне форматування (один користувач робить текст bold, інший одночасно — italic на перекриваючому діапазоні) — CRDT розв'язує автоматично: обидва атрибути застосовуються.
Складніше з семантично несумісними операціями: один користувач ставить H1 на абзац, інший — H2 на той же абзац. Y.js виберіть один (за clientId), але UI повинен про це попередити або дати інструмент ручного розв'язання.
Персистентність та історія
Y.js документ серіалізується у Uint8Array через Y.encodeStateAsUpdate(). Для персистентності на мобілі: зберігаємо в SQLite через expo-sqlite або react-native-sqlite-storage. При відкриванні документа: завантажуємо збережене стан, застосовуємо через Y.applyUpdate(), потім підключаємося до WebSocket й отримуємо diff від сервера.
Сервер повинен підтримувати y-leveldb або y-redis для зберігання стану документа. y-websocket сервер — мінімалістичний Node.js сервер з пакета, підходить для старту. Для production: persistence + auth + room access control.
Оцінка
Спільний редактор документів — комплексна задача. Orієнтири MVP (базовий текст + синхронізація + курсори) на React Native: 8–14 тижнів. Нативні iOS/Android з багатим форматуванням — 16–24 тижні. Істотна частина часу — нативний текстовий редактор, не мережева синхронізація.







