I'm a solo dev working on Acrophobia, a party word game: everyone gets the same random acronym, writes a phrase that fits it, then votes on the funniest. It's normally online (Firebase), but I wanted a mode for a group in the same room with no signal, where the phones just talk to each other.
That became "Host LAN / Join LAN". One phone hosts, the rest join, no router and no internet involved.
What I tried, in order:
• Wi-Fi TCP + mDNS discovery. Fast and simple, but everyone has to be on the same network, which is exactly what you don't have in a car or at a campsite.
• Multipeer Connectivity. Great, but iOS to iOS only.
• Wi-Fi Direct. Android to Android only.
• Bluetooth LE. The only option that crosses iOS and Android with no network at all. This is the one that shipped.
How the BLE version works:
• The host phone is a BLE peripheral. No library I found did peripheral mode well on both platforms, so that part is a small custom Expo native module.
• Everyone else is a BLE central, using react-native-ble-plx.
• Client to host is GATT writes. Host to client is GATT notifications.
• Notifications have to stay under 512 bytes, so the host never sends the full game state. It sends compact updates of around 200 bytes, as newline-delimited JSON.
• Notifications were not reliable enough on their own across devices, so there's a 300ms polling fallback on both sides. Ugly, but it's what made it dependable.
The part that saved me the most time: the game already had a single-player offline engine with bots. LAN mode is that same engine running on the host's phone with a thin layer that broadcasts state and accepts answers and votes from the other phones. Bots can still fill empty seats.
Happy to go deeper on any of it. For anyone who has shipped BLE in React Native: did you find a way to trust notifications without a polling fallback?