Bluetooth Low Energy

How do iPhone and Android phones message each other over Bluetooth?

They use Bluetooth Low Energy. One phone acts as the peripheral, advertising a service and hosting it in a GATT server, and the other acts as the central, scanning for that service, connecting and writing to or subscribing to its characteristics. Both apps must agree on the same service and characteristic identifiers, and each platform's permission and background rules decide when the link can form.

Learning objectives

After reading this article you will be able to:

  • Describe the central and peripheral roles an iPhone and an Android phone play
  • Explain how a message travels between phones through GATT writes and notifications
  • Identify where iOS and Android differ on permissions and background discovery

The common ground: Bluetooth LE roles

iOS and Android do not share a messaging service, but both let apps use Bluetooth Low Energy directly, and both expose the two roles that a BLE connection needs.

  • The central scans for advertisements and opens the connection. On the phone, this is what a fitness app does when it looks for a heart-rate strap.
  • The peripheral advertises and accepts the connection. It usually also acts as the GATT server, holding services and characteristics that the central can read, write and subscribe to.

Android’s BLE overview spells out why both roles matter: two devices that only support the central role cannot talk to each other, and neither can two that only support the peripheral role. So for an iPhone and an Android phone to talk, one has to play the strap’s part.

On iOS that is CBPeripheralManager, which publishes services into the phone’s GATT database and advertises them to centrals. On Android it is the BLE advertiser together with BluetoothGattServer. Either phone can take either role, and in apps where anyone may start a conversation, each phone runs both.

How a message travels from one phone to the other

The exchange looks the same whichever phone is which:

  1. Agree on identifiers. Both apps are built with the same service UUID and characteristic UUIDs. This is how they recognise each other among every other Bluetooth device in the room.
  2. Advertise. The peripheral phone advertises the service UUID.
  3. Scan and connect. The central phone scans, filters on that UUID, and connects to what it finds.
  4. Discover. The central discovers the peripheral’s services and characteristics.
  5. Exchange. To send, the central writes to a characteristic. To receive, it subscribes to notifications on another, and the peripheral pushes data through them.
  6. Frame and confirm. Android describes GATT as built for short pieces of data, so longer messages are split into chunks and reassembled, and the app usually sends its own acknowledgment once the whole message has arrived.

Nothing here is specific to iPhone or Android. That is the point: the protocol on top of GATT is yours, and as long as both apps implement it the same way, the operating systems do not need to know about each other.

Where iPhone and Android differ

The differences are in permissions and in what happens when the app is not on screen.

Permissions. On iOS, an app that uses Core Bluetooth must include the NSBluetoothAlwaysUsageDescription key in its Info.plist; Apple warns that the app crashes without it. An Android app that targets Android 12 or higher declares BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE and BLUETOOTH_CONNECT, which are runtime permissions the user grants. Android’s guide ties the first to looking for devices and the second to making the phone discoverable, so a phone-to-phone app that runs both roles asks for all three.

Background on iOS. Apple’s Core Bluetooth background guide matters most for a mixed pair. An iOS app that declares no Bluetooth background mode cannot scan while it is in the background, and its advertising stops. With the bluetooth-peripheral background mode it can keep advertising, but differently: the local name is not advertised, and the service UUIDs move into a special “overflow” area that, in Apple’s words, can be discovered only by an iOS device that is explicitly scanning for them.

For a mixed pair, that means an Android phone scanning for your service UUID may not find an iPhone whose app is in the background. A backgrounded iPhone with the bluetooth-central mode can still discover and connect to peripherals, though Apple notes that scanning happens less often when every scanning app is in the background. Many apps therefore make discovery work in both directions, test what happens with each phone in the background, and make it clear to users when the app needs to be open.

Does it work in practice?

Yes, when both sides implement the same protocol. Bitchat is an open-source example: its iOS app and its Android app are separate codebases, and the Android README describes the app as fully protocol-compatible with the iOS version for cross-platform mesh communication, with Bluetooth LE as the local transport.

The same approach works from a single cross-platform codebase, as long as the native layer underneath runs the peripheral role on both platforms. Not every Bluetooth library does: many are written for phones talking to accessories and only implement the central role, which is the subject of Can react-native-ble-plx connect two phones directly?

Bluetooth LE is not the only direct link a phone has, but it is the one whose phone-to-phone roles both platforms document for apps. Can an iPhone and an Android phone connect directly without internet? compares it with the Wi-Fi options.

Frequently asked questions

Can both phones be centrals and peripherals at once?

Yes, and in apps where either side may start the conversation they usually are. The app then needs a rule for which side opens the connection, so the two phones do not connect to each other twice.

Sources

Build it with Offline Protocol

The Offline Protocol quickstart runs the same React Native app, built for iOS and Android, on two physical phones and exchanges an encrypted message over Bluetooth LE with no account or server.

Read the quickstart