Another Flatiron student and I were interested in the Multipeer Connectivity Framework in iOS, so we made a chat app called Lattice that uses multipeer in the event of a natural disaster as a demonstration of the technology.
I’m going to talk about how the basics of multipeer connectivity work.
The Multipeer Connectivity (MC) Framework
What does it do?
Multipeer allows devices to connect with others nearby without the internet.
How does it work?
Multipeer Connectivity is an implementation of mesh networking, creating a local network between devices within Wifi or Bluetooth range. Not only are new devices connected with devices within range but also with all devices that those devices are connected to, even if the destination device is not within range of the sender.
That’s the real power of mesh networks. If permitted, devices can send messages relayed through other devices.
How might this be useful?
- Mesh networks allow communication when internet infrastructure is damaged (such as natural disasters).
- Mesh networks allow communication when internet access is restricted by governments, seen in the protests of Hong Kong.
- Mesh networks allow communication in internet-less situation (camping trips, road trips, subway commutes, and foreign vacations).
Lattice – Demo Project
Before we dive into the nitty gritty, I’ve placed Lattice on Github, so you can see exactly how the snippets below are used.
Setting up the MCManager
We have a MCManager class, similar to an API manager or data store for Core Data. Four properties need to be set up.
MCPeerID
_peerID = [[MCPeerID alloc] initWithDisplayName:displayName];
This is the name of your device.
MCSession
_session = [[MCSession alloc] initWithPeer:self.peerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
_session.delegate = self;
This is the session that your device will start. Think of a session like a chatroom.
MCNearbyServiceAdvertiser
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:elements serviceType:LatticeServiceType];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];
This adverser tells nearby browsers that it is looking to connect with a particular serviceType. DiscoveryInfo is a dictionary that the browser will receive when it finds this advertiser.
MCNearbyServiceBrowser
_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:LatticeServiceType];
self.browser.delegate = self;
[self.browser startBrowsingForPeers];
This browser looks for advertisers of a particular service type to connect to.
Connecting to Other Devices
Lattice, the demo app, will have an advertiser and browser running at the same time on each device.
Browser Finds Peer, Invites Peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
[self.browser invitePeer:peerID toSession:self.session withContext:nil timeout:10]
}
When a browser finds an advertiser, it can parse the discoveryInfo that the advertiser set when it was created. In this case, we want the devices to connect automatically, so the browser sends an invitation to connect to the browser’s session.
Advertiser Accepts Invitation
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler
{
invitationHandler(YES, self.session);
}
Since we want the advertiser to connect automatically, the advertiser will reply YES to the invitation.
Session Confirms Connection
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
We can indeed confirm that the two devices are connected with this delegate method from the session. The session will tells us that the peer is now in the connected state.
Sending and Receiving Messages
Sending From the View Controller
[self.multipeerManager.session sendData:messageData toPeers:self.multipeerManager.session.connectedPeers withMode:MCSessionSendDataUnreliable error:&error];
Messages are sent from the session to the peers in the session.
Receiving In the MCManager
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
//Kicks off a notification to the View Controller
}
Messages are received by the session on the other devices. In Lattice, we triggered a notification with each message received.
Catching the Notification In the View Controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(peerDidReceiveDataWithNotification:) name:@"MCDidReceiveDataNotification" object:nil];
- (void)peerDidReceiveDataWithNotification:(NSNotification *)notification
{
NSData *messageData = notification.userInfo[@"data"];
NSArray *messages = [NSKeyedUnarchiver unarchiveObjectWithData:messageData];
[self.demoData.messages addObject:messages[0]];
}
The notification was handled by the view controller to display the new message.
Limitations
iOS only
Multipeer Connectivity is a iOS framework.
Range can be limited on Bluetooth
We found it to be about 60 – 100 feet.
Downloading the app requires the internet?!
There should be a way for the app to spread virally with no internet.
Limited usefulness in zombie apocalypse
This would be great for finding survivors nearby without having to go room by room through scary dark buildings. During night when the zombies are outside, the bluetooth signal may not be long enough to communicate between buildings.
Special Thanks
Peter Fennema for showing how to connect via multipeer automatically
Jesse Squires for the messaging user interface: JSQMessagesViewController