Bubble Chat and TSNPeerBluetooth Cocoapod... / by Brian Lambert

As part of the Developer Experiences team at Microsoft, I've been contributing to an open source project we're working on called Thali. (Visit thaliproject.org for more information on Thali).

Part of my work on Thali has been to investigate what is possible for peer-to-peer networking on iOS using Apple's Core Bluetooth and Multipeer Connectivity frameworks.

Inspired by apps like FireChat, I wanted to see how difficult it would be to develop a chat app for iOS that worked entirely over Bluetooth LE.

I called this app Bubble Chat. Here's a video showing Bubble Chat in action:

How Bubble Chat Works

Conceptually, there is one, worldwide bubble in Bubble Chat. Each user running Bubble Chat has a different view of this bubble that varies and is based solely on the set of nearby peers it can communicate with on Bluetooth LE over time. So, when another user running Bubble Chat enters your Bluetooth LE communications range, they enter your view of the bubble and you enter their view of the bubble, and the two of you can communicate with each other for as long as you remain within range. When two peers are out of Bluetooth LE communications range, they can no longer communicate with one another and their views of the bubble will diverge accordingly.

It's kind of neat concept, and it's also sort of pointless. :-) But that's OK. I only built Bubble Chat to be an example of how one might use Apple's Core Bluetooth framework for peer-to-peer networking.

The Code

Here's a link to the Bubble Chat repo on Guthub.

Bubble Chat makes use of a Cocoapod I wrote called TSNPeerBluetooth. Here's a link to the TSNPeerBluetooth repo on Github.

I should note that TSNPeerBluetooth isn't designed to be a generally useful Cocoapod for other applications. It was built solely for Bubble Chat and to serve as a useful, standalone iOS example of how to define a custom Bluetooth LE service and set of characteristics, act as a peripheral for that service, and as a central that consumes that service.

Development Notes

On iOS, an app can act as both a Bluetooth LE accessory (it can be a Bluetooth LE peripheral, in Core Bluetooth parlance) and it can use Bluetooth LE accessories (it can be a Bluetooth LE central, in Core Bluetooth parlance).

When an app is in the foreground, all of this works as you would expect. A foreground app is allowed to use Bluetooth LE as it sees fit to meet its needs.

When an app is in the background, however, things work quite differently.

Apple works very, very hard to keep iOS apps that are in the background from consuming resources (using the radios, using the GPS receiver, running code, etc.) so that battery usage for background apps, and thus the device itself, remains very low.

By default, when an iOS application is in the background it can't do anything. (The exception being that one can use a background task to complete work that was being done when the app was put into the background, but only for a short, unspecified period of time.) 

Apple provides a way for an app to do certain things in the background by declaring what it needs to do in Capabilities / Background Modes:

The Bubble Chat application declares three such Background Modes:

  1. Location updates in the background.
  2. Uses Bluetooth LE accessories in the background.
  3. Acts as a Bluetooth LE accessory in the background.

Declaring these Background Modes seems like it would allow an app to do everything in the background that it can do in the foreground with respect to receiving location updates, using Bluetooth LE accessories, and acting as a Bluetooth LE accessory. This isn't the case, though. In particular, when an iOS app is in the background, Bluetooth LE behaves very differently. This is a very long and complicated topic which is covered in some detail in the Core Bluetooth Background Processing for iOS Apps documentation. But this documentation doesn't tell the entire story. In particular, it does not discuss why it is that an iOS app such as Bubble Chat - which acts as both a Bluetooth LE peripheral and central - cannot discover and connect to other instances of itself when all instances are in the background.

  • When an iOS device that's acting as a peripheral goes into the background, it changes its advertisement packets to not include service UUIDs.
  • When an iOS device that's acting as a central goes into the background, it only scans for specific service UUIDs.

These two background behaviors combine to prevent background-to-background iOS advertisement / discovery.

There are numerous postings about this topic on Stack Overflow and other sites which erroneously claim that background-to-background iOS advertisement / discovery is possible. As of iOS 8.3, it is not possible.

I contacted Apple support about this and, after a few iterations, they have acknowledged that it is indeed true and have instructed me to file a bug report / enhancement request for it. I filed enhancement request #20655911 on 23-Apr-2015.

Here's a video which illustrates background-to-background iOS advertisement / discovery:

I'm continuing to work on Bubble Chat and TSNPeerBluetooth, and I welcome your thoughts, ideas, and contributions.