iOS Multipeer Connectivity question...
If an MCNearbyServiceAdvertiser declines the invitation from an MCNearbyServiceBrowser via calling:
invitationHandler(NO, nil);
...in:
advertiser:didReceiveInvitationFromPeer:withContext:invitationHandler:
...is there a way for the MCNearbyServiceBrowser
to know that the invitation was specifically declined?
I do see that the device using MCNearbyServiceBrowser
receives a session state change to MCSessionStateNotConnected
when the advertiser declines the invitation, but I would imagine that the browsing device might receive MCSessionStateNotConnected
for other reasons, too...like the advertiser device going away (turned off, etc).
Any suggestions on how to distinguish a declined invitation from some other kind of disconnection?
Thank you.
-Allan
As per the docs, MCSessionStateNotConnected
can signify that
"...the nearby peer declined the invitation, the connection could not be established, or a previously connected peer is no longer connected."
You don't say in your question what would cause an invitation to be declined, but assuming that it is user-driven, one approach could be having your MCNearbyServiceAdvertiserDelegate
automatically accepting invitations, creating a new session for each peer, and then presenting the user with the choice of accepting or declining the connection. Your peers would not be considered truly in session with each other until they had received a follow-up message indicating the user's decision:
So in your MCNearbyServiceAdvertiserDelegate
class you'd accept and then prompt the user:
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler {
//Automatically accept with a new session
MCSession *newSession = [[MCSession alloc] initWithPeer:_myPeerID];
newSession.delegate = self;
//Keep track of the pending sessions in a mutable dictionary
_pendingSessionPeerIDMap[peerID.displayName] = newSession;
invitationHandler(YES,newSession);
/* Code here to present user with option to accept or decline peer */
}
And then when the user has responded you could have a method that sends a simple string as NSData containing the status:
@property NSData *inviteAcceptedMsgData = [@"MPCInviteYES" dataUsingEncoding:NSUTF8StringEncoding];
@property NSData *inviteDeclinedMsgData = [@"MPCInviteNO" dataUsingEncoding:NSUTF8StringEncoding];
- (void)invitationFromPeerID:(MCPeerID *)peerID receivedResponse:(BOOL)accepted {
//Send a message to the peer that sent the invitation indicating whether the
//user accepted or declined
NSData *msgData = (accepted) ? _inviteAcceptedMsgData : _inviteDeclinedMsgData;
MCSession *peerSession = _pendingSessionPeerIDMap[peerID.displayName];
[peerSession sendData:msgData
toPeers:@[peerID]
withMode:MCSessionSendDataReliable
error:nil];
//Remove the pending session
[_pendingSessionPeerIDMap removeObjectForKey:peerID.displayName];
//And if the connection was accepted by the user, add to an accepted dictionary
_acceptedSessionPeerIDMap[peerID.displayName] = peerSession;
}
The MCNearbyServiceBrowserDelegate
would work in a similar way:
- (void)browser:(MCNearbyServiceBrowser *)browser
foundPeer:(MCPeerID *)peerID
withDiscoveryInfo:(NSDictionary *)info {
//Send the invitation with a new session
MCSession *newSession = [[MCSession alloc] initWithPeer:_myPeerID];
newSession.delegate = self;
[browser invitePeer:peerID
toSession:newSession
withContext:nil
timeOut:0];
}
Then the browser would wait for a message from the peer it invited to determine whether the invitation was truly accepted:
- (void)session:(MCSession *)session
didReceiveData:(NSData *)data
fromPeer:(MCPeerID *)peerID {
//Check the data to see whether invite was accepted
if ([data isEqualToData:_inviteAcceptedMsgData]) {
//Add to an accepted dictionary
_acceptedSessionPeerIDMap[peerID.displayName] = session;
}
else if ([data isEqualToData:_inviteAcceptedMsgData]){
//Disconnect the session
[session disconnect];
}
}
You may already have a messaging system in place but this represents a simple implementation of passing state between connected peers. As far as sending broadcasts or displaying connected peers is concerned, the _acceptedSessionPeerIDMap
should be used as the true collection of peers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With