All case studies

Case Study

HyperBleKit: Offline Multiplayer Between Android and iOS over Bluetooth Alone

Before building a turn-based multiplayer game whose players always sit in the same room, we spent a two-day coworking sprint finding out whether the phones could talk to each other directly over Bluetooth Low Energy, with no internet and no backend. This is what we expected from each technical challenge, what actually happened, and where the limits are.

Project
HyperBleKit — open-source BLE multiplayer SDK
Platforms
Native Android (Kotlin) and iOS (Swift)
Format
Two-day coworking sprint, five-person team
Status
v0.1.0, unit-tested on both platforms

TL;DR

  • —Our upcoming turn-based game is always played in one room, so we dropped the internet and the backend and let the phones talk over Bluetooth Low Energy.
  • —In a two-day coworking sprint (October 2–3, 2026) five of us built a prototype on mixed Android and iOS devices and stress-tested it with seven games.
  • —We wrote the transport natively in Kotlin and Swift, and kept the two implementations identical with a written spec and shared byte-for-byte test vectors.
  • —Cross-platform connections were the hardest part; transfer speed is enough for turn-based and simpler real-time games as long as messages stay small.
  • —The number of simultaneously connected phones is the real limit: it can be pushed but not removed, because it depends on the hardware.
  • —The result is HyperBleKit, an open-source SDK at version 0.1.0: unit-tested, but not yet tested on real phones in its packaged form.

Players in the same room do not need a server

We are preparing to develop a turn-based multiplayer game whose players are always physically together. That made it possible to drop the internet and the backend entirely and let the phones talk to each other directly. After evaluating the options, we chose Bluetooth Low Energy (BLE).

Before committing a product to that decision, we tested it. In a two-day coworking sprint on October 2–3, 2026, a five-person team built and validated a prototype on mixed Android and iOS devices. We stress-tested it with seven games, from turn-based card games to real-time action games, and later refined the results into an open-source SDK, HyperBleKit.

The host role forced us to go native on both platforms

In a BLE session the hosting phone must act as a peripheral: it advertises the game and runs a GATT server that the other phones connect to. At the time, most cross-platform BLE libraries supported only the central (client) role on one or both platforms, so a single shared codebase could not reliably provide the role our architecture depended on.

We implemented the transport natively on each platform, Kotlin on Android and Swift on iOS, to keep full control over advertising and the GATT server, and accepted the cost of writing the protocol twice. Both platforms now host and join sessions, and Android and iOS devices communicated well in practice. The host exposes three characteristics:

  • —Game info, which clients read
  • —Client-to-host, which clients write
  • —Host-to-client, delivered as notifications

A written spec and shared test vectors kept two codebases identical

The price of going native was the risk of two implementations drifting apart, and two independent implementations of a wire protocol tend to diverge silently. On top of that, emulators and simulators do not support real BLE radio, so the protocol could not be verified end to end without physical phones.

So we wrote the specification first and treated it as the single source of truth. We checked in shared test vectors, canonical JSON messages with their exact chunked byte frames, that both platforms must reproduce byte for byte. And we designed a strictly layered architecture in which the protocol and the game logic run against fake, in-process transports.

Both platforms pass the same vectors, which proves wire compatibility on a laptop without pairing a single phone. Discovery, sessions, games and the relay logic were all unit-tested before real radios were involved, and a shared, timestamped debug log format let us compare Android and iPhone logs side by side during real-device testing. HyperBleKit inherited the approach: its test suite runs entirely without Bluetooth.

Android and iOS disagree at almost every step of a connection

This proved to be the hardest part of the project. Android splits its advertisement so that the scan response arrives after the main packet, not every Android device can advertise as a host, and the two platforms handle connection state and device caching differently. Connections that worked within one platform did not necessarily work across platforms.

Our approach was to test Android against iOS early, feed every discovered quirk back into the specification, and fix the transport on whichever side was at fault. The spec now reflects real-world behaviour: the game code travels in Android's manufacturer data, for example, and the app checks whether a device supports advertising before offering to host.

After a cross-platform interop review we hardened the Android transport's device caching and connection handling. Mixed-platform sessions then connected and stayed connected reliably.

Message size is a design constraint, not a detail

BLE is designed for small packets, while a game needs to exchange structured messages that can be considerably larger than a single packet, especially with richer content such as card artwork or real-time updates. We built a protocol layer to bridge that gap, plus a dedicated real-time frame lane for real-time games, kept separate from the reliable message flow.

With small JSON messages and a moderate number of connected devices, the transfer speed was sufficient not only for turn-based games but for simpler real-time games too. Performance drops as payloads grow and as more devices share the host's connection, so any game built on this stack has to treat message size as a design constraint.

  • —MTU negotiation, chunking and reassembly
  • —Sequence numbers and acknowledgements
  • —Retries and deduplication
  • —A separate real-time frame lane next to the reliable message flow

The player limit can be pushed, but the hardware sets it

In a star topology every player connects to the host, and a single phone acting as a GATT server can hold only a limited number of simultaneous connections. The limit depends on the device's Bluetooth chipset, and it is the real barrier between a small group and a larger one.

We first applied capacity fixes to the host's BLE handling, then raised the player limit deliberately, from 5 to 10 and then to 16, to find the breaking point. Finally we went beyond the star with a relay tree, in which intermediate phones forward traffic for the host so the network can fan out further than one radio can hold.

The ceiling moved to a certain extent, but a hard upper limit remains and it varies from device to device. The relay tree was built and tested on Android with fake-transport tests and ported to iOS, but the iOS port was not built or verified during the sprint. The SDK currently states a limit of up to 10 players.

A stable device ID makes reconnection and host migration possible

Phones drop out of BLE sessions. A dropped player needs to get back into the same seat, and the session must survive if the host leaves or disappears, which also means the remaining phones have to find the new host. A further complication is that iOS rotates the device's Bluetooth address, so devices cannot be recognised by their address.

We specified reconnection and host migration in the README before implementing them, then implemented them on both platforms in lockstep. Each player is identified by a stable, randomly generated device ID, and reconnection is performed by game code. That ID is what made it possible to return a player to their seat and hand the session over to another phone. Both capabilities became core features of HyperBleKit.

What the sprint proved, and what it did not

The sprint answered the question it was designed to answer: offline multiplayer between Android and iOS over BLE alone is feasible. Cross-platform communication works, and transfer speed is sufficient for turn-based and simpler real-time games as long as messages stay compact. The main constraint is the number of simultaneously connected devices, which can be pushed but not eliminated.

We consolidated the work into HyperBleKit, an open-source SDK for Android and iOS that separates the BLE networking from the application logic. It is currently at version 0.1.0: unit-tested on both platforms, but not yet tested on real phones in its packaged form.

What we learned building HyperBleKit

  • ✓If your players are always in the same room, question whether you need a server at all.
  • ✓When a cross-platform library does not cover the role your architecture depends on, go native and budget for writing the protocol twice.
  • ✓Two implementations of one protocol stay compatible only if a written spec and shared byte-for-byte test vectors force them to.
  • ✓Layer the code so that everything above the radio runs against fake transports; real devices are then needed only for what is truly device-specific.
  • ✓Test Android against iOS from day one: a connection that works within one platform proves little about the other.
  • ✓Treat message size and player count as product constraints from the first design conversation, because the hardware will enforce them anyway.

Does your app have to work where there is no internet?

We prototype the riskiest technical question first, on real Android and iOS devices, and tell you honestly what works and where the limits are before you commit a budget to it.

Get a free estimate