Flatiron School Presents – The Multipeer Connectivity Framework (Lattice)

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?

  1. Mesh networks allow communication when internet infrastructure is damaged (such as natural disasters).
  2. Mesh networks allow communication when internet access is restricted by governments, seen in the protests of Hong Kong.
  3. 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

Flatiron School Week 9 – Conquering Fear of Complex CocoaPods

For my Flatiron School Presents project, a classmate and I worked on a chat app.

For the chat user interface, I wanted it to look like Apple’s Messages app. There was a perfect CocoaPod for this: JSQMessagesViewController. After reading the Getting Started section, I still had no clue how to bridge the gap between my existing app and this UI. It was overwhelming and I was very discouraged.

9 Steps to Overcoming Fear of Complex CocoaPods

Step 1: Recognizing the problem

I knew that I was avoiding it. I looked for another CocoaPod but they weren’t quite the same. I even thought of building my own chat UI. I realized that I needed to be able to use CocoaPods though, so there was no getting around it.

Step 2: Read Zen Pencils

In need of inspiration, I turned to the Zen Pencils. I have the book too, which makes for very motivating reading.

Step 3: Go to sleep

It was 9 already and so I figured it was better to get some sleep than try that night.

Step 4: Try a simpler CocoaPod.

I hadn’t used enough CocoaPods up to this point, so I tried a smaller one. I looked at HPL chat. It had a tenth as many classes as JSQ did and I went for it. It didn’t work, but got me started.

Step 5: Look at the demo

The challenge of open source software is that there’s not always good documentation. It doesn’t cost money, but it costs time to read and understand how to use the code.

Fortunately, I saw that JSQ had a demo and downloaded it. Playing around with the demo really helped me understand how the pieces related to each other.

Step 6: Start customizing the demo

I didn’t need images or videos so, I got rid of the accessory button on the toolbar. I had to get familiar with the documentation to find which parts I needed to change. Once I removed the button, I felt much more confident about adapting the demo.

Step 7: Move the demo to a new project and make it work

Now I tried to make the demo fit my purpose, removing as much as I could to reduce it to the elements I needed. Here was a sandbox that I could use to unit test the functionality before I put it into my app and get everything tangled up.

Step 8. Add to the app

With the chat working on it’s own, I had to hook it up to my project. By this point, I realized that I just needed to make a couple  subclasses of the classes that the CocoaPod needed and replace my existing messages class with those.

Step 9. Fear Conquered

After I was done, I read the CocoaPod’s Getting Started again and now it all makes sense. Going through implementing this pod has been a process of gradual building of exposure, comfort and confidence with CocoaPods. I’m really happy that I did this. Fear of technology really comes down to not understanding how it works.