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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Getting Started with Multipeer Connectivity
30 mins
Seeing Connected Peers
The chat room isn’t helpful if you can’t see who’s joined. So in session(_:peer:didChange:)
, find the following cases
:
case .connected:
print("Connected")
case .notConnected:
print("Not Connected")
Then replace them with code below:
case .connected:
if !peers.contains(peerID) {
// 1
DispatchQueue.main.async {
self.peers.insert(peerID, at: 0)
}
// 2
if isHosting {
sendHistory(to: peerID)
}
}
case .notConnected:
DispatchQueue.main.async {
// 3
if let index = self.peers.firstIndex(of: peerID) {
self.peers.remove(at: index)
}
// 4
if self.peers.isEmpty && !self.isHosting {
self.connectedToChat = false
}
}
In the previous section, you used this method to know when to send jobs. Here, you’re using it to do the following:
- If a user connects to the chat, add them to the list of peers.
- If you’re the host, send the entire chat history to the newly connected user. You’ll implement this later.
- When a person disconnects, remove them from the list of peers.
- If the host and all the other peers leave, end the session automatically.
Build and run on both devices, hosting on one and joining on the other. You’ll now see both users in the top of the chat, like below:
Sending Data to Multiple Devices
Now you’re ready to start sending messages between users! In ChatConnectionManager.swift, replace send(_:)
with the following code:
func send(_ message: String) {
// 1
let chatMessage = ChatMessage(
displayName: myPeerId.displayName,
body: message)
messages.append(chatMessage)
// 2
guard
let session = session,
let data = message.data(using: .utf8),
!session.connectedPeers.isEmpty
else { return }
do {
// 3
try session.send(data, toPeers: session.connectedPeers, with: .reliable)
} catch {
print(error.localizedDescription)
}
}
Here’s a breakdown of the code above:
- Create a
ChatMessage
with the relevant data needed for local use. - Encode the message string.
- Use
MCSession
to send to all the connected peers.
Next, replace session(_:didReceive:fromPeer:)
with the following:
func session(
_ session: MCSession,
didReceive data: Data,
fromPeer peerID: MCPeerID
) {
guard let message = String(data: data, encoding: .utf8) else { return }
let chatMessage = ChatMessage(displayName: peerID.displayName, body: message)
DispatchQueue.main.async {
self.messages.append(chatMessage)
}
}
Build and run on both devices, and create a chat session between the two. You’ll see the following:
If you leave the chat and come back, you’ll see the chat history is gone. You can remedy this by sending the entire chat history to users as they join.
Replace sendHistory(to:)
with the following:
func sendHistory(to peer: MCPeerID) {
// 1
let tempFile = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent("messages.data")
guard let historyData = try? JSONEncoder().encode(messages) else { return }
// 2
try? historyData.write(to: tempFile)
// 3
session?.sendResource(
at: tempFile,
withName: "Chat_History",
toPeer: peer
) { error in
if let error = error {
print(error.localizedDescription)
}
}
}
This code will execute on the hosting device. Here’s what happens:
- Create the URL in your temporary directory.
- Write the chat history to a file at this URL.
- Use
MCSession
to send a resource instead ofData
.
Since you’re not sending data directly, you’ll need to use a different delegate method of MCSessionDelegate
. Replace session(_:didFinishReceivingResourceWithName:fromPeer:at:withError:)
with the following:
func session(
_ session: MCSession,
didFinishReceivingResourceWithName resourceName: String,
fromPeer peerID: MCPeerID,
at localURL: URL?,
withError error: Error?
) {
// 1
guard
let localURL = localURL,
let data = try? Data(contentsOf: localURL),
// 2
let messages = try? JSONDecoder().decode([ChatMessage].self, from: data)
else { return }
DispatchQueue.main.async {
// 3
self.messages.insert(contentsOf: messages, at: 0)
}
}
This code executes on the peer connecting to the session. Here’s what’s happening:
- If the resource was successfully saved locally on your device, you receive the URL here.
- The content of the file is decoded into
ChatMessage
. - The messages are inserted in your local messages, which display when you join the chat.
Build and run on both devices. Create a chat session and send messages between both devices, like below:
On the devices you used to join the session, choose Leave:
Rejoin the same session, and you’ll see the entire chat history, as found below:
Where to Go From Here?
You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.
You should now feel comfortable using Multipeer Connectivity and sending communication between devices without the internet. There’s still more to learn, such as sending and receiving streams between devices.
You can learn more by checking out more of our iOS & Swift Tutorials or by referring to Apple’s documentation.
We hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!