Multipeer Connectivity iOS Tutorial

The multipeer connectivity framework let users connect and send data to each other. In this tutorial a chat app is create, which lets user send messages. For this tutorial a iOS device is needed next to the iOS Simulator. This tutorial is made with Xcode 10 and built for iOS 12.

Open Xcode and create a new Single View App.

For product name, use IOSMultipeerConnectivityTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.

Go to the Storyboard and select the View Controller. Go to the Editor menu and select Embed in -> Navigation Controller. Select the main view from the ViewController and go to the Attributes inspector. In the View section change the background color to Light Gray Color

Go to the Object Library and drag a Text View onto the main view. Select the Text View and go to the Attribute inspector. In the Text View Section delete the placeholder text, so the Text View will be empty. Also deselect the Editable Behaviour checkbox. The Text View will only be used for output of the chat messages.

Drag a Text Field from the Object Library and place it below the Text View. This Text Field will be used to enter the chat message.

Drag a button from the Object Library and place it below the Text Field. Change the text to Send. This button will be used to send the entered message and to display the message in the Text View.

Select the Resolve Auto Layout Issues button and select Reset to Suggested Constraints.

The Storyboard should look like this.

Select the Assistant Editor and make sure the ViewController.swift is visible. Ctrl and drag from the Text View to the ViewController class and create the following Outlet.

Ctrl and drag from the Text Field to the ViewController class and create the following Outlet

Ctrl and drag from the Send Button to the ViewController class and create the following Action.

Go to the ViewController.swift file and import the MultipeerConnectivity framework

import MultipeerConnectivity

Add the MCSessionDelegate and MCBrowserViewControllerDelegate protocol to the ViewController class definition

class ViewController: UIViewController, MCSessionDelegate, MCBrowserViewControllerDelegate {

Add the following properties

var peerID: MCPeerID!
var mcSession: MCSession!
var mcAdvertiserAssistant: MCAdvertiserAssistant!
var messageToSend: String!
  • MCPeerID identifies the user inside a session

  • MCSession handles multipeer connectivity

  • MCAdvertiserAssistant advertise sessions and handles invitations

  • The messageToSend is a plain String to display onto the Text View

Change the viewDidLoad() method to

override func viewDidLoad() {
  super.viewDidLoad()
  // 1
  navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(showConnectionMenu))

  // 2
  peerID = MCPeerID(displayName: UIDevice.current.name)
  mcSession = MCSession(peer: peerID, securityIdentity: nil, encryptionPreference: .required)
  mcSession.delegate = self

}
  1. The share bar button item is placed on to the navigation bar. When clicked the showConnectedMenu method will be called. This method will be implemented shortly.

  2. Create a multipeer session with the name of the device as the peerID.

Implement the showConnectionMenu() method

@objc func showConnectionMenu() {
  let ac = UIAlertController(title: "Connection Menu", message: nil, preferredStyle: .actionSheet)
  ac.addAction(UIAlertAction(title: "Host a session", style: .default, handler: hostSession))
  ac.addAction(UIAlertAction(title: "Join a session", style: .default, handler: joinSession))
  ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
  present(ac, animated: true)
}

A session can be created (hosted) or an existing session can be joined. Implement the hostSession(action:) and joinSession(alert:) methods

// 1
func hostSession(action: UIAlertAction) {
  mcAdvertiserAssistant = MCAdvertiserAssistant(serviceType: "ioscreator-chat", discoveryInfo: nil, session: mcSession)
  mcAdvertiserAssistant.start()
}

// 2
func joinSession(action: UIAlertAction) {
  let mcBrowser = MCBrowserViewController(serviceType: "ioscreator-chat", session: mcSession)
  mcBrowser.delegate = self
  present(mcBrowser, animated: true)
}
  1. An advertiser assistant object is initialized with an unique serviceType string.

  2. The MCBrowserViewController class presents nearby devices to the user and enables the user to invite nearby devices to a session

Implement the

@IBAction func tapSendButton(_ sender: Any) {
  // 1
  messageToSend = "\(peerID.displayName): \(inputMessage.text!)\n"
    let message = messageToSend.data(using: String.Encoding.utf8, allowLossyConversion: false)
    
    do {
      // 2
      try self.mcSession.send(message!, toPeers: self.mcSession.connectedPeers, with: .unreliable)
      chatView.text = chatView.text + messageToSend
      inputMessage.text = ""
    }
    catch {
      print("Error sending message")
    }
  }
  1. The message variable is assigned a Data object containing a String.

  2. Sends a message encapsulated in a Data instance to nearby peer

Next, the delegate methods must be implemented to conform to the MCSessionDelegate and MCBrowserViewControllerDelegate protocol.

// 1
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
  switch state {
  case .connected:
    print("Connected: \(peerID.displayName)")
  case .connecting:
    print("Connecting: \(peerID.displayName)")
  case .notConnected:
    print("Not Connected: \(peerID.displayName)")
  @unknown default:
    print("fatal error")
  }
}

// 2
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
  DispatchQueue.main.async { [unowned self] in
    // send chat message
    let message = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)! as String
    self.chatView.text = self.chatView.text + message
  }
}

func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {

}

func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {

}

func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {

}

// 3
func browserViewControllerDidFinish(_ browserViewController: MCBrowserViewController) {
  dismiss(animated: true)
}

func browserViewControllerWasCancelled(_ browserViewController: MCBrowserViewController) {
  dismiss(animated: true)
}
  1. This delegate method is called when the state of a nearby peer changes. The state is printed to the console.

  2. When a message is received the data object is converted to a string and printed to the text view.

  3. The BrowserViewController is dismissed when the session is finished or cancelled.

Build and Run the project on the simulator and an iOS device. Select the share icon on one of the instances and host a session and then join the existing session

Next, add a message in the text field, this message will be received by the narby peers and printed to the text view.


The source code of the IOSMultipeerConnectivityTutorial can be downloaded at the ioscreator repository on Github.