I am using the Multipeer Connectivity Framework on macOS, and I am trying to implement the functionality of connecting to other peers. I used a MCNearbyServiceBrowser
and displayed the found peers in an NSTableView
. I also have a NSTextField
for people to enter their display name, which will be the display name of their MCPeerID
.
The workflow is as follows: The user enter a display name, selects a peer from the NSTableView
, and press the connect button.
This means that I don't have an MCPeerID
until the connect button is pressed, because before that time the textfield text could still change. However, initialising a MCNearbyServiceBrowser
requires an MCPeerID
, so I thought I could use a dummy peer ID for the browser, then create the real one when the connect button is pressed, like this:
let dummyPeerID = MCPeerID(displayName: "Unnamed")
override func viewDidLoad() {
browser = MCNearbyServiceBrowser(peer: dummyPeerID, serviceType: "some identifier")
...
}
@IBAction func connect(_ sender: NSButton) {
let peerID = MCPeerID(displayName: displayNameTextField.stringValue)
session = MCSession(peer: peerID)
session.delegate = self
activityIndicator.isHidden = false
activityIndicator.startAnimation(nil)
// selectedTeacher is an RxSwift.Variable<MCPeerID?> that is bound to the selected model object of the table view
browser.invitePeer(selectedTeacher.value!, to: session, withContext: nil, timeout: 10)
}
When I run this code, I saw that session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState)
is called with a state
of .notConnected
, and this is printed in the console:
Wrong connection data. Participant ID from remote connection data = 7008A6B3, local participant ID = 4F1F9C8D.
I suppose that it means I can't use different MCPeerID
s for the browser and the session. If I change this line:
session = MCSession(peer: peerID)
to:
session = MCSession(peer: dummyPeerID)
Then it is connected to the session correctly.
What can I do in this situation, where I don't know the display name of the local peer when browsing for other peers? (Let's assume we can't change the UI design)
I can think of two solutions: using data contexts or using a second browser
Using data contexts
Use your dummy id but don't rely on its displayName property. Instead pass your real display name via the context parameter of invitePeer(_ peerID: MCPeerID, to session: MCSession, withContext context: Data?, timeout: TimeInterval)
@IBAction func connect(_ sender: NSButton) {
session = MCSession(peer: dummyPeerID)
session.delegate = self
activityIndicator.isHidden = false
activityIndicator.startAnimation(nil)
browser.invitePeer(
selectedTeacher.value!,
to: session,
withContext: displayNameTextField.stringValue.data(using: .utf8)!,
timeout: 10
)
}
Using a second browser
Create a new MCPeerID and create a second browser with your new MCPeerID
. Wait until the selectedTeacher is discovered again using your second browser and then use that browser with the new ID to invite the selectedTeacher.
var dummyBrowser: InvitingBrowser?
@IBAction func connect(_ sender: NSButton) {
let peerID = MCPeerID(displayName: displayNameTextField.stringValue)
session = MCSession(peer: peerID)
session.delegate = self
activityIndicator.isHidden = false
activityIndicator.startAnimation(nil)
// selectedTeacher is an RxSwift.Variable<MCPeerID?> that is bound to the selected model object of the table view
dummyBrowser = InvitingBrowser(
session: session,
serviceType: mcService,
remote: selectedTeacher.value!
)
}
class InvitingBrowser: NSObject, MCNearbyServiceBrowserDelegate {
let browser: MCNearbyServiceBrowser
var remote: MCPeerID
let session: MCSession
init(session: MCSession, serviceType: String, remote: MCPeerID) {
browser = MCNearbyServiceBrowser(peer: session.myPeerID, serviceType: serviceType)
self.remote = remote
self.session = session
super.init()
browser.delegate = self
browser.startBrowsingForPeers()
}
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
if peerID == remote {
browser.invitePeer(peerID, to: session, withContext: nil, timeout: 30)
browser.stopBrowsingForPeers()
}
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {}
}