Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MCNearbyServiceBrowser know whether MCNearbyServiceAdvertiser declined an invitation?

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

like image 953
lagouyn Avatar asked Jun 29 '14 08:06

lagouyn


1 Answers

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.

like image 144
ChrisH Avatar answered Nov 03 '22 19:11

ChrisH