Getting Started with Multipeer Connectivity

In this tutorial, you’ll learn how to transfer data between devices with no external network. You’ll also try your hand at creating a chat feature. By Andy Pereira.

Leave a rating/review
Download materials
Save for later
Share

Most people think of the internet when asked how to transfer data between devices. With today’s modern devices and increasing cellular and Wi-Fi coverage, it seems logical. Yet, there are still cases where the internet may not be available to your users and they still need to transfer data. Think of a time you needed to send a photo to someone you were with, perhaps while traveling abroad. Or maybe you needed to send a file to a coworker in a crowded airport. These are a few connectivity examples users of your app may encounter while in the real world.

Apple’s Multipeer Connectivity framework introduces a way to send and receive data between users of your app. Multipeer Connectivity uses your device’s networking hardware, such as Bluetooth and Wi-Fi, without requiring an internet connection. Think about the last time you used AirDrop to send a photo or web page to someone. Both devices were likely not on the same network, but they were still able to send information from one device to another. Multipeer Connectivity is the same framework that powers AirDrop, and it’s available for you to include in your app.

In this tutorial, you’ll learn how to:

  • Advertise your device to other users of your app.
  • Browse for users that are advertising.
  • Send custom data between devices.
  • Host a session multiple users can join.
  • Send data to multiple users at the same time.
  • Send files stored on your device to another user.
Note: For this tutorial, you’ll need to run the project on two different devices. This can be any combination of physical devices or simulators.

Getting Started

To get started, click the Download Materials button at the top or bottom of this tutorial to download the resources you’ll need. Open the starter project in the starter folder.

The app you’ll use, Job Manager, provides managers and employees with a way to create and assign jobs to each other. It also lets employees host or join chat rooms with other nearby employees.

Build and run, and you’ll see the following:

App running after downloading materials

Now you’ll move on to advertising your device.

Advertising Your Device

To get started, open Info.plist and add the following entry:

  • Key: Privacy — Local Network Usage Description
  • Value: Job Manager needs to use your phone’s data to discover devices nearby

Apple requires this key to inform users why your app will use the local network. In networking, a local network is one in which devices share the same means of communication. When using Multipeer Connectivity, you’re creating a new local network for devices to connect to.

Next, open JobConnectionManager.swift and add the following:

import MultipeerConnectivity

This will ensure you can use the Multipeer Connectivity framework in this file.

Next, add the following to JobConnectionManager.swift inside the class declaration:

// 1
private let session: MCSession
// 2
private let myPeerId = MCPeerID(displayName: UIDevice.current.name)
private let jobReceivedHandler: JobReceivedHandler?

init(_ jobReceivedHandler: JobReceivedHandler? = nil) {
  // 3
  session = MCSession(
    peer: myPeerId,
    securityIdentity: nil,
    encryptionPreference: .none)
  // 4
  self.jobReceivedHandler = jobReceivedHandler
}

Here’s a breakdown of the code above:

  1. MCSession is the class used to handle all communication between devices.
  2. MCPeerID identifies your device on the local network. In this example, you’re using the name you set for your phone.
  3. Initialize your session with your peer ID. You can choose whether you want encryption used for your messages. It’s not used here.
  4. You’ll see more on this last line a little later.

This app allows employees to determine whether they want to allow jobs to be sent to their phone through Advertising. To implement Advertising, add the following properties to JobConnectionManager:

private static let service = "jobmanager-jobs"
private var nearbyServiceAdvertiser: MCNearbyServiceAdvertiser

MCNearbyServiceAdvertiser is the class that will handle making your device discoverable through MCSession. One of the requirements to advertise is that you have a service. The next step will cover this.

Now, add the following to the initializer of JobConnectionManager:

nearbyServiceAdvertiser = MCNearbyServiceAdvertiser(
  peer: myPeerId,
  discoveryInfo: nil,
  serviceType: JobConnectionManager.service)

Here, you initialized nearbyServiceAdvertiser with a Service Type. Multipeer Connectivity uses the service type to limit the way it handles discovering advertised devices. In this project, JobConnectionManager will only be able to discover devices that advertise with the service name of jobmanager-jobs.

Next, add the following to JobConnectionManager.swift, at the end of the file below the class declaration:

extension JobConnectionManager: MCNearbyServiceAdvertiserDelegate {
  func advertiser(
    _ advertiser: MCNearbyServiceAdvertiser,
    didReceiveInvitationFromPeer peerID: MCPeerID,
    withContext context: Data?,
    invitationHandler: @escaping (Bool, MCSession?) -> Void
  ) {
  }
}

Once your device is advertising that it’s available for jobs, it’ll need a way to handle requests to connect and receive the job. MCNearbyServiceAdvertiserDelegate needs to handle this request. Here, you can decide whether you want your app to automatically accept the invitation or ask users if they want to allow the connection.

To handle the invitation, add the following to advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler:):

guard 
  let window = UIApplication.shared.windows.first,
  // 1
  let context = context,
  let jobName = String(data: context, encoding: .utf8) 
else {
  return
}
let title = "Accept \(peerID.displayName)'s Job"
let message = "Would you like to accept: \(jobName)"
let alertController = UIAlertController(
  title: title,
  message: message,
  preferredStyle: .alert)
alertController.addAction(UIAlertAction(
  title: "No",
  style: .cancel
) { _ in
  // 2
  invitationHandler(false, nil)
})
alertController.addAction(UIAlertAction(
  title: "Yes",
  style: .default
) { _ in
  // 3
  invitationHandler(true, self.session)
})
window.rootViewController?.present(alertController, animated: true)

In the code above, when the app receives an invitation, it displays an alert asking the user to accept or decline the job. There are three important things to focus on here:

  1. The context passed in gets converted to a string. When you get to the section about sending data, you’ll see how this happens. For now, you need to understand that any type of Data can be passed here and converted however you need.
  2. The invitationHandler closure is says whether the advertising device wants to accept a connection. This is how you cancel the invitation.
  3. If the user chooses to accept the connection, pass invitationHandler your current MCSession.

Now, add the following to the end of the initializer of JobConnectionManager:

super.init()
nearbyServiceAdvertiser.delegate = self

Here, you set the delegate for your advertiser, which will show the alert when an invitation is sent.

You’re almost done setting up your device to advertise itself! Only a few more steps.

Add the following property to JobConnectionManager:

var isReceivingJobs: Bool = false {
  didSet {
    if isReceivingJobs {
      nearbyServiceAdvertiser.startAdvertisingPeer()
      print("Started advertising")
    } else {
      nearbyServiceAdvertiser.stopAdvertisingPeer()
      print("Stopped advertising")
    }
  }
}

You likely won’t want to have your device advertising itself as being available all the time. Here, you start or stop advertising based on the value of isReceivingJobs.