MCNearbyServiceBrowser邀请陌生Peer卡在MCSessionStateConnecting无法连接
问题根因
按照优先级排序,最可能导致连接卡在MCSessionStateConnecting的原因如下:
- MCPeerID无效:Multipeer Connectivity框架中,
MCPeerID不是仅靠displayName做唯一标识的,内部包含框架生成的唯一标识符。如果你的strangerPeerWithStrangerName方法是根据传入的用户名重新创建了MCPeerID实例,而不是返回扫描时foundPeer回调拿到并存入strangersPeerID数组的原始实例,那么这个新建的PeerID对于浏览器来说是完全无效的,无法匹配到真实扫描到的设备,导致连接无响应。 - 浏览器未处于活跃扫描状态:
MCNearbyServiceBrowser只有在调用startBrowsingForPeers后的活跃状态下,才能向之前发现过的节点发起邀请。如果扫描到陌生人后你调用了stopBrowsingForPeers停止扫描,后续再用同一个浏览器实例发起邀请会直接失效。 - 对端邀请逻辑拦截:你本地把陌生人标记为好友仅修改了本地状态,对端设备上你仍然属于陌生人,若对端的
MCNearbyServiceAdvertiser的didReceiveInvitationFromPeer回调中仅接受好友的邀请,会直接忽略你的邀请请求,你这边就会一直卡在连接状态直到超时。 - 会话冲突:如果之前和目标节点有未销毁的旧
MCSession关联,新建会话发起连接时会出现内部冲突,导致连接无法正常推进。
解决方案
1. 修复MCPeerID获取逻辑
修改strangerPeerWithStrangerName方法,直接从foundPeer回调时存入的strangersPeerID数组中匹配返回原始实例,不要手动新建MCPeerID:
- (MCPeerID *)strangerPeerWithStrangerName:(NSString *)name { for (MCPeerID *peer in self.strangersPeerID) { if ([peer.displayName isEqualToString:name]) { return peer; } } return nil; }
2. 保证邀请时浏览器处于活跃状态
发起邀请前先检查浏览器状态,未在扫描则先重启扫描,确保邀请请求能正常发出,同时清理旧会话避免冲突:
- (void)strangerDidBecameFriend:(NSString *)newFriend { MCPeerID *strangerPeer = [self strangerPeerWithStrangerName:newFriend]; if (!strangerPeer) return; // 确保浏览器处于活跃扫描状态 if (!self.browser.isBrowsing) { [self.browser startBrowsingForPeers]; // 延迟1秒保证扫描就绪后再发起邀请 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self inviteStrangerPeer:strangerPeer]; }); } else { [self inviteStrangerPeer:strangerPeer]; } } // 抽离邀请逻辑 - (void)inviteStrangerPeer:(MCPeerID *)peer { // 先清理和该节点关联的旧会话 NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(MCSession *session, NSDictionary *bindings) { return [session.connectedPeers containsObject:peer] || session.delegate == self; }]; NSArray *oldSessions = [self.sessions filteredArrayUsingPredicate:predicate]; for (MCSession *oldSession in oldSessions) { [oldSession disconnect]; [self.sessions removeObject:oldSession]; } MCSession *session = [[MCSession alloc] initWithPeer:self.sharerPeer securityIdentity:nil encryptionPreference:MCEncryptionNone]; [session setDelegate:self]; [self.sessions addObject:session]; [self.browser invitePeer:peer toSession:session withContext:nil timeout:10]; }
3. 调整对端邀请处理逻辑
对端收到邀请时不要直接拦截陌生人请求,可以在邀请的context参数中携带自己的用户标识,对端收到邀请后先校验用户身份,若属于待同意的好友申请则直接调用invitationHandler(YES, session)同意连接。
4. 补充校验回调
实现MCSession的证书校验回调,即使使用无加密模式也主动返回同意,避免框架默认校验拦截连接:
- (void)session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL))certificateHandler { certificateHandler(YES); }
内容的提问来源于stack exchange,提问作者Mingxian Zhao
相关产品推荐
相关产品推荐

