Social Features in Mobile Applications: Chat, VoIP, Feed and Reactions
Adding chat to application — this is not "use Socket.io and display messages". This is offline access, history display on poor connection, typing indicators, read statuses, push notifications when app closed, and all this must work on Android 8 with 512MB RAM without ANR.
Chat Architecture: WebSocket, XMPP, or Ready SDK
WebSocket — protocol, not architecture. Bare WebSocket without protocol on top — this is reinventing wheel. Minimum: define message format, heartbeat mechanism, reconnection strategy, queue of unsent messages on connection loss.
In practice for product chats we use one of three solutions:
Ready-made chat SDK — SendBird, Stream Chat, Cometchat. Provide UI components, server infrastructure, push notifications, moderation. Fast, reliable, but vendor lock-in and recurring costs.
Firebase Realtime Database / Firestore — for simple chats without >100K concurrent users scalability requirements. Realtime Database better for chat (ordered message lists), Firestore — for more structured data. Limitation: no built-in typing indicators and presence — implemented separately via onDisconnect().
Own backend with WebSocket — full control, maximum customization. Tech stack: WebSocket via socket.io (Node.js) or Phoenix Channels (Elixir) + PostgreSQL + Redis for pub/sub. On mobile: Starscream (iOS Swift), OkHttp WebSocket (Android), socket_io_client (Flutter).
Offline mode — most labor-intensive part. Messages saved in SQLite (iOS: GRDB, Android: Room) with local ID, synchronized on connection restore. Conflicts on simultaneous sending resolved via vector clock or server-timestamp ordering.
VoIP: CallKit, ConnectionService and WebRTC
VoIP in mobile application — two different scenarios: look like phone call (system call UI) or just audio/video call inside app.
CallKit (iOS) allows integrating VoIP call into system interface: application appears on Lock Screen as regular call, works with Bluetooth headsets, interrupts other audio. Implemented via CXProvider + CXCallController. Plus: application launches via VoIP push (PKPushKit) even when killed — mandatory for receiving incoming calls.
On Android equivalent — ConnectionService API. More complex integration, behavior varies between manufacturers (Xiaomi, Samsung with their battery optimization aggressively kill background processes).
WebRTC — transport protocol for peer-to-peer media. WebRTC on iOS via GoogleWebRTC pod or native RTCPeerConnection. On Flutter — flutter_webrtc. Signaling server (SDP, ICE candidates exchange) — usually via same WebSocket channel as chat.
STUN/TURN servers — mandatory infrastructure. Without TURN ~15-20% users behind symmetric NAT cannot establish P2P connection. coturn — open source TURN server, Twilio NTS and Metered TURN — managed options.
Feed and Reactions
Infinite feed — UICollectionView with UICollectionViewDiffableDataSource on iOS, LazyColumn with Paging 3 on Android. Pagination via cursor-based approach (not offset) — on new elements insertion cursor doesn't shift, offset shifts, user sees duplicate content.
Reactions (emoji on messages) — technically: each reaction — separate DB record (message_id, user_id, emoji). Aggregation on server: GROUP BY emoji. WebSocket event reaction_added updates counter in real-time. Reaction appearance animation — via withSpring (Reanimated) or Core Animation spring on iOS.
Push notifications for social events: @mention, reply to comment, new follower — all via APNs (iOS) and FCM (Android). For rich notifications (with media preview) on iOS — Notification Service Extension loading media before display.
| Feature | Ready-Made SDK | Custom Implementation |
|---|---|---|
| Basic chat | SendBird, Stream | WebSocket + Room/GRDB |
| VoIP | Twilio, Agora | WebRTC + CallKit |
| Feed | — | Paging 3 / DiffableDataSource |
| Push for social events | Firebase FCM/APNs | APNs direct |
Timeline: basic chat with history and push — 4-6 weeks. VoIP calls with CallKit/ConnectionService — 3-5 weeks. Full-featured social feed with reactions, comments and notifications — from 3 months.







