iOS Multipeer Connectivity didReceiveInvitationFromPeer did not - ios

I know this question has been asked many times, but after reading each of them more than a few times, I still can't get my Multipeer Connectivity to work. I am sending but not receiving the invitation. Here is the code:
#implementation MPCManager
- (id)init {
self = [super init];
if (self) {
_myPeerID = nil;
_session = nil;
_browser = nil;
_advertiser = nil;
}
return self;
}
- (void)automaticBrowseAndAdvertiseWithName:(NSString *)displayName {
_myPeerID = [[MCPeerID alloc] initWithDisplayName:displayName];
_session = [[MCSession alloc] initWithPeer:_myPeerID];
_session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:_myPeerID
discoveryInfo:nil
serviceType:#"trm-s"];
_advertiser.delegate = self;
[_advertiser startAdvertisingPeer];
_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:_myPeerID
serviceType:#"trm-s"];
_browser.delegate = self;
[_browser startBrowsingForPeers];
}
- (void)session:(MCSession *)session
didReceiveCertificate:(NSArray *)certificate
fromPeer:(MCPeerID *)peerID
certificateHandler:(void (^)(BOOL accept))certificateHandler {
certificateHandler(YES);
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void (^)(BOOL,
MCSession *))invitationHandler {
NSLog(#"This is NOT getting called");
}
- (void)browser:(MCNearbyServiceBrowser *)browser
didNotStartBrowsingForPeers:(NSError *)error {
NSLog(#"%#", [error localizedDescription]);
}
- (void)browser:(MCNearbyServiceBrowser *)browser
foundPeer:(MCPeerID *)peerID
withDiscoveryInfo:(NSDictionary *)info {
NSLog(#"This IS getting called");
}
- (void)invitePeer:(MCPeerID *)peerID {
NSLog(#"This IS getting called");
[_browser invitePeer:peerID toSession:_session withContext:nil timeout:30];
}
I am running it on two simulators, and it was working for some time, but stopped suddenly. Any ideas on how or where to look for the problem?

Make sure that you are serializing and reusing your MCPeerID objects whenever possible. Each time you call - (instancetype)initWithDisplayName:(NSString *)myDisplayName it returns a unique instance.
What often happens in a dev environment is that you end up with a flood of advertisers and browsers and a ton of ghost duplicates in the Bonjour advertising space. This can cause everything to just go wonky.
If you are using simulators then resetting them may help. On hardware you can restart or toggle airplane mode.
Take a look at this year's WWDC session on Multipeer named "Cross Platform Nearby Networking". It has some good best practices to follow that will help immensely.

Related

Multipeer Connection issue with ipv6 don't get an invitation

My App was rejected by Apple because it can't connect to other device running iOS 10.1.1 on Wi-Fi connected to an IPv6 network.
When I tap on connect, the app continues to search for invitees and no further user action is produced.
I use Multi-peer Connectivity and I never tested my App being connected to an IPv6(It's my first release). But the App run very fine without having any connection or being connected to IPv4 network.
I don't know why the App is running and connecting fine using the IPv4 and doesn't connect to peer if the iPad is connected to an IPv6 network.
So my Question: Is it possible to use Multi-peer Connectivity with IPv6 so that Apple can approve the App or how should I handle this Issue ?
Here is my Code, maybe it is something wrong there.
#interface ConnectionManageriOS7 () <MCSessionDelegate, MCBrowserViewControllerDelegate>
{
UILocalNotification *_expireNotification;
UIBackgroundTaskIdentifier _taskId;
}
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCPeerID *localPeerID;
#property (nonatomic, strong) MCBrowserViewController *browserVC;
#property (nonatomic, strong) MCAdvertiserAssistant *advertiser;
#end
static ConnectionManageriOS7 *_manager = nil;
#implementation ConnectionManageriOS7
+ (ConnectionManageriOS7 *)connectManager {
#synchronized([ConnectionManageriOS7 class]){
if (_manager == nil) {
_manager = [[ConnectionManageriOS7 alloc] init];
}
return _manager;
}
return nil;
}
- (id)init {
self = [super init];
if (self) {
[self setupSessionAndAdvertiser];
}
return self;
}
- (void)setupSessionAndAdvertiser {
_localPeerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];;
_session = [[MCSession alloc] initWithPeer:_localPeerID];
_session.delegate = self;
}
- (void)connectWithDelegate:(id)delegate {
_delegate = delegate;
if (_session.connectedPeers.count) {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
} else {
if (_advertiser == nil) {
_advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:VISUS_Service
discoveryInfo:nil
session:_session];
_isConnected = NO;
[_advertiser start];
}
if (_browserVC == nil) {
_browserVC = [[MCBrowserViewController alloc] initWithServiceType:VISUS_Service session:_session];
_browserVC.delegate = self;
}
[(UIViewController *)delegate presentViewController:_browserVC
animated:YES completion:nil];
}
}
- (void)sendMessage:(NSString *)message {
NSData *textData = [message dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"Send Data: %#", message);
NSError *error = nil;
[_session sendData:textData
toPeers:_session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
if (error) {
// 
[self session:_session peer:nil didChangeState:MCSessionStateNotConnected];
NSLog(#"error %#", error.userInfo);
}
}
- (void)stopService {
NSLog(#"Stop Service");
[_advertiser stop];
_advertiser = nil;
_browserVC = nil;
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void) dismissBrowserVC{
[_browserVC dismissViewControllerAnimated:YES completion:nil];
}
// Notifies the delegate, when the user taps the done button
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
[self dismissBrowserVC];
}
// Notifies delegate that the user taps the cancel button.
- (void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController{
if (_browserVC == nil) {
[browserViewController dismissViewControllerAnimated:YES completion:nil];
}else {
[self dismissBrowserVC];
}
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
_isConnected = true;
if ([_delegate respondsToSelector:#selector(willConntectedWithManager:)]) {
[_delegate willConntectedWithManager:self];
}
}
else {
_isConnected = false;
[self stopService];
if ([_delegate respondsToSelector:#selector(didDisconntectedWithManager:)]) {
[_delegate didDisconntectedWithManager:self];
}
}
}
}
// Received data from remote peer
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
// Decode data back to NSString
NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Receive Data: %#", message);
// append message to text box:
dispatch_async(dispatch_get_main_queue(), ^{
if ([_delegate respondsToSelector:#selector(connectionManager:receivedString:)]) {
[_delegate connectionManager:self receivedString:message];
}
});
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error {
_isConnected = false;
[self stopService];
NSLog(#"----- Error ----- %#", error.localizedDescription);
}
// Received a byte stream from remote peer
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID {
}
// Start receiving a resource from remote peer
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress {
}
- (void) session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler
{
certificateHandler(YES);
}
- (void) createExpireNotification
{
[self killExpireNotification];
if (_session.connectedPeers.count != 0) // if peers connected, setup kill switch
{
NSTimeInterval gracePeriod = 20.0f;
// create notification that will get the user back into the app when the background process time is about to expire
NSTimeInterval msgTime = UIApplication.sharedApplication.backgroundTimeRemaining - gracePeriod;
UILocalNotification* n = [[UILocalNotification alloc] init];
_expireNotification = n;
_expireNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:msgTime];
_expireNotification.alertBody = #"Bluetooth Connectivity is about to disconnect. Open the app to resume Test";
_expireNotification.soundName = UILocalNotificationDefaultSoundName;
_expireNotification.applicationIconBadgeNumber = 1;
[UIApplication.sharedApplication scheduleLocalNotification:_expireNotification];
}
}
- (void) killExpireNotification
{
if (_expireNotification != nil)
{
[UIApplication.sharedApplication cancelLocalNotification:_expireNotification];
_expireNotification = nil;
}
}
- (void)bacgroundHandling {
_taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
{
[self stopService];
[[UIApplication sharedApplication] endBackgroundTask:_taskId];
_taskId = UIBackgroundTaskInvalid;
}];
[self createExpireNotification];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
// http://down.vcnc.co.kr/WWDC_2013/Video/708.pdf -- wwdc tutorial, this part is towards the end (p119)
// self.arrayInvitationHandler = [NSArray arrayWithObject:[invitationHandler copy]];
// ask the user
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:peerID.displayName
message:#"Would like to create a session with you"
delegate:self
cancelButtonTitle:#"Decline" otherButtonTitles:#"Accept", nil];
[alertView show];
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// retrieve the invitationHandler and check whether the user accepted or declined the invitation...
BOOL accept = (buttonIndex != alertView.cancelButtonIndex) ? YES : NO;
// respond
if(accept) {
// void (^invitationHandler)(BOOL, MCSession *) = [self.arrayInvitationHandler objectAtIndex:0];
// invitationHandler(accept, self.mySession);
}
else
{
NSLog(#"Session disallowed");
}
}
- (void)terminate {
[self killExpireNotification];
[self stopService];
}
#end
I have solved the problem. For everybody with simular problem:
It wasn't a problem with IPv6, it is a matter of how to use Multipeer connectivity. In my Case I tryied to the the IPv6 connection with a iPad and a Simulator. And I used my Macbook for creating a nat64 network. And the reason why the simulator and iPad never saw each other the fact that they where not connected to same wifi network.
Solution:
Just take for testing two iPads and use your mac as nat64 network accesspoint.

Multipeer Connectivity on iOS never connects?

I'm trying to use Multipeer Connectivity to connect iPhone Simulator on my mac with my iPhone. The app will get to the MCBrowserViewController, where I'll tap the iPhone Simulator and send an invitation to it. Then, I'll accept the invitation from my Mac and my phone will show me a "connecting..." However, the connection never succeeds, even though my mac and phone are less than 4 inches apart. This also doesn't work in reverse (i.e. when I send the invite from my mac)
I've tried the suggestions in this link but neither having separate advertiser and browser sessions nor commenting out the didReceiveCertificate seems to be working.
- (void)setupPeerWithDisplayName:(NSString *)displayName {
self.peerID = [[MCPeerID alloc] initWithDisplayName:displayName];
}
- (void)setupSession {
self.advertiseSession = [[MCSession alloc] initWithPeer:self.peerID];
self.advertiseSession.delegate = self;
self.browserSession = [[MCSession alloc] initWithPeer:self.peerID];
self.browserSession.delegate = self;
}
- (void)setupBrowser {
self.browser = [[MCBrowserViewController alloc] initWithServiceType:#"m117" session:self.browserSession];
}
- (void)advertiseSelf:(BOOL)advertise {
if (advertise) {
self.advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:#"m117" discoveryInfo:nil session:self.advertiseSession];
[self.advertiser start];
} else {
[self.advertiser stop];
self.advertiser = nil;
}
}
...
-(void)session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL))certificateHandler {
certificateHandler(YES);
}

Why is Multipeer Connectivity so slow?

So, I have all multipeer connectivity related code in the main thread. I have a MCSession, MCNearbyServiceAdvertiser, and a MCNearbyServiceBrowser. These are all created with peerID, and I make sure only one sends an invitation.
The session becomes connected. My problems is that, two clients take around 20-30 seconds to connect. This is unacceptable. The clients are on good Wifi, and bluetooth. I want the browsing, invitation handler, and connection to take place within 1 second. Does anyone have any idea what is slowing things down?
Code is exactly as provided here and I also implemented certificateHandler(YES)
#interface SessionController () // Class extension
#property (nonatomic, strong) MCPeerID *peerID;
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCNearbyServiceAdvertiser *serviceAdvertiser;
#property (nonatomic, strong) MCNearbyServiceBrowser *serviceBrowser;
// Connected peers are stored in the MCSession
// Manually track connecting and disconnected peers
#property (nonatomic, strong) NSMutableOrderedSet *connectingPeersOrderedSet;
#property (nonatomic, strong) NSMutableOrderedSet *disconnectedPeersOrderedSet;
#end
#implementation SessionController
static NSString * const kMCSessionServiceType = #"mcsessionp2p";
#pragma mark - Initializer
- (instancetype)init
{
self = [super init];
if (self)
{
_peerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
_connectingPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
_disconnectedPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
// Register for notifications
[defaultCenter addObserver:self
selector:#selector(startServices)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[defaultCenter addObserver:self
selector:#selector(stopServices)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[self startServices];
_displayName = self.session.myPeerID.displayName;
}
return self;
}
#pragma mark - Memory management
- (void)dealloc
{
// Unregister for notifications on deallocation.
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Nil out delegates
_session.delegate = nil;
_serviceAdvertiser.delegate = nil;
_serviceBrowser.delegate = nil;
}
#pragma mark - Override property accessors
- (NSArray *)connectedPeers
{
return self.session.connectedPeers;
}
- (NSArray *)connectingPeers
{
return [self.connectingPeersOrderedSet array];
}
- (NSArray *)disconnectedPeers
{
return [self.disconnectedPeersOrderedSet array];
}
#pragma mark - Private methods
- (void)setupSession
{
// Create the session that peers will be invited/join into.
_session = [[MCSession alloc] initWithPeer:self.peerID];
self.session.delegate = self;
// Create the service advertiser
_serviceAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID
discoveryInfo:nil
serviceType:kMCSessionServiceType];
self.serviceAdvertiser.delegate = self;
// Create the service browser
_serviceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID
serviceType:kMCSessionServiceType];
self.serviceBrowser.delegate = self;
}
- (void)teardownSession
{
[self.session disconnect];
[self.connectingPeersOrderedSet removeAllObjects];
[self.disconnectedPeersOrderedSet removeAllObjects];
}
- (void)startServices
{
[self setupSession];
[self.serviceAdvertiser startAdvertisingPeer];
[self.serviceBrowser startBrowsingForPeers];
}
- (void)stopServices
{
[self.serviceBrowser stopBrowsingForPeers];
[self.serviceAdvertiser stopAdvertisingPeer];
[self teardownSession];
}
- (void)updateDelegate
{
[self.delegate sessionDidChangeState];
}
- (NSString *)stringForPeerConnectionState:(MCSessionState)state
{
switch (state) {
case MCSessionStateConnected:
return #"Connected";
case MCSessionStateConnecting:
return #"Connecting";
case MCSessionStateNotConnected:
return #"Not Connected";
}
}
#pragma mark - MCSessionDelegate protocol conformance
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
NSLog(#"Peer [%#] changed state to %#", peerID.displayName, [self stringForPeerConnectionState:state]);
switch (state)
{
case MCSessionStateConnecting:
{
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
}
case MCSessionStateConnected:
{
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
}
case MCSessionStateNotConnected:
{
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
break;
}
}
[self updateDelegate];
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
// Decode the incoming data to a UTF8 encoded string
NSString *receivedMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"didReceiveData %# from %#", receivedMessage, peerID.displayName);
}
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
NSLog(#"didStartReceivingResourceWithName [%#] from %# with progress [%#]", resourceName, peerID.displayName, progress);
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error
{
NSLog(#"didFinishReceivingResourceWithName [%#] from %#", resourceName, peerID.displayName);
// If error is not nil something went wrong
if (error)
{
NSLog(#"Error [%#] receiving resource from %# ", [error localizedDescription], peerID.displayName);
}
else
{
// No error so this is a completed transfer. The resources is located in a temporary location and should be copied to a permenant location immediately.
// Write to documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *copyPath = [NSString stringWithFormat:#"%#/%#", [paths firstObject], resourceName];
if (![[NSFileManager defaultManager] copyItemAtPath:[localURL path] toPath:copyPath error:nil])
{
NSLog(#"Error copying resource to documents directory");
}
else
{
// Get a URL for the path we just copied the resource to
NSURL *url = [NSURL fileURLWithPath:copyPath];
NSLog(#"url = %#", url);
}
}
}
// Streaming API not utilized in this sample code
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
{
NSLog(#"didReceiveStream %# from %#", streamName, peerID.displayName);
}
#pragma mark - MCNearbyServiceBrowserDelegate protocol conformance
// Found a nearby advertising peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
NSString *remotePeerName = peerID.displayName;
NSLog(#"Browser found %#", remotePeerName);
MCPeerID *myPeerID = self.session.myPeerID;
BOOL shouldInvite = ([myPeerID.displayName compare:remotePeerName] == NSOrderedDescending);
if (shouldInvite)
{
NSLog(#"Inviting %#", remotePeerName);
[browser invitePeer:peerID toSession:self.session withContext:nil timeout:30.0];
}
else
{
NSLog(#"Not inviting %#", remotePeerName);
}
[self updateDelegate];
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
{
NSLog(#"lostPeer %#", peerID.displayName);
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
[self updateDelegate];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
{
NSLog(#"didNotStartBrowsingForPeers: %#", error);
}
#pragma mark - MCNearbyServiceAdvertiserDelegate protocol conformance
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
NSLog(#"didReceiveInvitationFromPeer %#", peerID.displayName);
invitationHandler(YES, self.session);
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
[self updateDelegate];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
{
NSLog(#"didNotStartAdvertisingForPeers: %#", error);
}
#end
I've noticed this issue to and i can't seem to figure out whats happening here, it appears when debugging that there is a huge delay between the notification for state changing being fired, perhaps something to do with the view itself.
Update: Well i think i figured the issues out after a bit of reading, the response is pretty much instant now, in the notification in the view i have pushed the process back to the main thread like so:
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification{
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:#"state"] intValue];
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
// add the user
[arrConnectedDevices addObject:peerDisplayName];
}
else if (state == MCSessionStateNotConnected){
// do we have connections
if ([arrConnectedDevices count] > 0) {
int indexOfPeer = [arrConnectedDevices indexOfObject:peerDisplayName];
[arrConnectedDevices removeObjectAtIndex:indexOfPeer];
}
}
}
// push to main queue for speedy response
dispatch_async(dispatch_get_main_queue(), ^(void) {
[collView reloadData];
BOOL peersExist = ([[appDelegate.mcManager.session connectedPeers] count] == 0);
NSLog(#"PEER COUNT IS %lu",(unsigned long)[[appDelegate.mcManager.session connectedPeers] count]);
[disconnectButton setEnabled:!peersExist];
if ([disconnectButton isEnabled]) {
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(51/255.0) green:(202/255.0) blue:(168/255.0) alpha:1.0]];
}
else{
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(107/255.0) green:(107/255.0) blue:(107/255.0) alpha:1.0]];
}
});
}
Hope this helps anyone who ran into the issues.

MultiPeer Framework Delegates Not Firing/Running (No UI)

I've been stuck on this problem for a while. I'm trying test the multi peer framework. And I'm trying to do it without a UI. In other words, I'm inviting other peers manually through code. I want to be able for the app to come up, and the peers automatically start looking for each other and connect.
To do this I set up a class named SideWaysManager as so:
/**
SidewaysManager.m
*/
#import "SidewaysManager.h"
#import "EPBmyConfig.h"
#implementation SidewaysManager
{
NSString *databasePath;
MCSession *currentSession;
MCNearbyServiceBrowser *nearbyBrowser;
MCNearbyServiceAdvertiser *nearbyAdvertiser;
NSString *serviceType;
}
- (id) init
{
self = [super init];
if(self)
{
EPBmyConfig *configInfo = [EPBmyConfig instance];
NSString *assetID = [configInfo getAssetID];
NSString *useageLocation = [configInfo getUseageLocation];
NSString *peerDisplayName = [#"PCTouchPad-" stringByAppendingString:assetID];
if(![useageLocation isEqualToString:#""])
{
peerDisplayName = [peerDisplayName stringByAppendingString: [NSString stringWithFormat:#"-%#", useageLocation]];
}
MCPeerID *localPeerID = [[MCPeerID alloc] initWithDisplayName:peerDisplayName];
currentSession = [[MCSession alloc] initWithPeer:localPeerID];
currentSession.delegate = self;
serviceType = #"EPB-Session";
nearbyBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:localPeerID serviceType:serviceType];
nearbyBrowser.delegate = self;
nearbyAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:localPeerID discoveryInfo:nil serviceType:serviceType];
nearbyAdvertiser.delegate = self;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
databasePath = [documentDir stringByAppendingString:#"/voterdb_Prod"];
[nearbyAdvertiser startAdvertisingPeer];
[nearbyBrowser startBrowsingForPeers];
return self;
}
return self;
}
/**
Session delegates
*/
// Remote peer changed state
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
if(state == MCSessionStateConnected)
{
[nearbyAdvertiser stopAdvertisingPeer];
[nearbyBrowser stopBrowsingForPeers];
NSLog(#"Peer connected to session");
}
else if(state == MCSessionStateNotConnected)
{
NSLog(#"Peer not connected");
}
}
// Received data from remote peer
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
}
// Start receiving a resource from remote peer
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
}
// Finished receiving a resource from remote peer and saved the content in a temporary location - the app is responsible for moving the file to a permanent location within its sandbox
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error
{
}
- (void)session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void(^)(BOOL accept))certificateHandler
{
NSLog(#"Received certificate");
certificateHandler(YES);
}
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
{
stream.delegate = self;
[stream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[stream open];
}
/**
MCBrowser Delegates
*/
// Found a nearby advertising peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
NSLog(#"Found Peer");
[browser invitePeer:peerID toSession:currentSession withContext:nil timeout:0];
}
// A nearby peer has stopped advertising
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
{
NSLog(#"Lost Peer");
}
/**Advertising Delegates
*/
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
invitationHandler(YES, currentSession);
}
// Advertising did not start due to an error
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
{
NSLog(#"Did not start advertising");
}
#end
And here's my SideWaysManager.h file:
#import <Foundation/Foundation.h>
#import <MultipeerConnectivity/MultipeerConnectivity.h>
#interface SidewaysManager : NSObject <MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate, NSStreamDelegate>
#end
And then I initialize this class in my AppDelegate class. But, for some reason NONE of the delegate methods above run. Can any one familiar with the framework help me out or have any idea why nothing is happening in this class? I would greatly appreciate it.
I have created a project based on the Single View Application template. I added your SideWaysManager code to the project. To make it compile I removed the EPBmyConfig import and fixed the compilation errors as shown below:
// EPBmyConfig *configInfo = [EPBmyConfig instance];
// NSString *assetID = [configInfo getAssetID];
// NSString *useageLocation = [configInfo getUseageLocation];
NSString *peerDisplayName = #"PCTouchPad-Test";
// if(![useageLocation isEqualToString:#""])
// {
// peerDisplayName = [peerDisplayName stringByAppendingString: [NSString stringWithFormat:#"-%#", useageLocation]];
// }
MCPeerID *localPeerID = [[MCPeerID alloc] initWithDisplayName:peerDisplayName];
Running the code on my iPhone and simulator the delegates methods were called and a session was created. So it seems that your setup of the Multipeer Connectivity objects is OK.
How do you create the SideWaysManager in your AppDelegate?
This is how I did it:
#interface PFAppDelegate ()
#property (strong, nonatomic) SidewaysManager *manager;
#end
#implementation PFAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.manager = [[SidewaysManager alloc]init];
return YES;
}
It is important that your AppDelegate class holds a reference to the manager, otherwise it will be de-alloced immediately after didFinishLaunchingWithOptions returns. This could explain that nothing happens in your code.
Alternatively, their might be a problem in the creation of the peer display name (basically the stuff that I commented out).

GKLocalPlayer authentication not working, but isAuthenticated returns YES (Game Center sandbox)

I'm working on integrating turn based matches in my game and a few days ago I started getting weird errors from the GameKit API saying that the local player is not authenticated, even though he is.
When I launch the app, the authenticateHandler is called, the view controller is displayed and after entering the password, the authenticaHandler is called again and the local player seems to be authenticated. isAuthenticated returns YES.
But as soon as I start using any of the GameKit APIs like loadFriendsWithCompletionHandler:, an error is returned saying that the player has not been authenticated.
This is the code for handling authentication changes.
[[GKLocalPlayer localPlayer] setAuthenticateHandler:^(UIViewController *viewController, NSError *error) {
if ([[GKLocalPlayer localPlayer] isAuthenticated]) {
// Player authenticated
} else {
// Player not authenticated
if (viewController != nil) {
// Present view controller
}
}
}];
And this is the error message I receive when calling any of the GameKit methods. Please note that -isAuthenticated still returns YES when the error is returned.
Error finding match: Error Domain=GKErrorDomain Code=6 "The requested operation could not be completed because local player has not been authenticated." UserInfo=0x14e9f950 {NSLocalizedDescription=The requested operation could not be completed because local player has not been authenticated.}
(lldb) print (BOOL) [[GKLocalPlayer localPlayer] isAuthenticated]
(BOOL) $3 = YES
I'm testing in the Game Center sandbox and it started happening a few days ago. Previously, I didn't experience the problem at all.
It only happens about one of three times when the app is started. I have tried deleting the app, restarting my devices, cleaning the build folder and everything else I could think of.
Am I missing something or has anybody else experienced similar problems?
This rich Apple documentation is a great place to look at. Here are 2 things which I would suggest -
Game Center fails to complete authentication if your device has
incorrect dates. So, go ahead and check the current date.
You might have done this. I trust you - iOS Simulator >> Reset
Content and Settings
Do you think there could be something wrong with the way you are using -[GKLocalPlayer loadFriendsWithCompletionHandler:]? Nothing wrong with your authentication function above, but I'd love to share mine if it works for you -
-(void)authenticateLocalPlayer{
// Instantiate a GKLocalPlayer object to use for authenticating a player.
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
// If it's needed display the login view controller.
[self presentViewController:viewController animated:YES completion:nil];
}
else {
if ([GKLocalPlayer localPlayer].authenticated) {
// If the player is already authenticated then indicate that the Game Center features can be used.
_gameCenterEnabled = YES;
}
else {
_gameCenterEnabled = NO;
}
}
};
}
Why are you using Game Kit Framework?
From iOS 7 you should use MultipeerConnectivity.
1) – authenticateWithCompletionHandler: Deprecated in iOS 6.0.
And if you test on iOS 7 it may be doesn't work at all.
2) Below example for create connection via MultipeerConnectivity
Client:
- (id)init {
self = [super init];
if (self) {
NSString *peerName = [NSString stringWithFormat:#"%#-%#", #"Client", [[UIDevice currentDevice] identifierForVendor].UUIDString];
self.myPeerID = [[MCPeerID alloc] initWithDisplayName:peerName];
self.servers = [NSMutableArray array];
self.session = [[MCSession alloc] initWithPeer:self.myPeerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
self.session.delegate = self;
self.browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.myPeerID serviceType:#"Connect"];
self.browser.delegate = self;
[self.browser startBrowsingForPeers];
}
return self;
}
//-----
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {
NSLog(#"client: found a server: %#", peerID);
[self.browser invitePeer:peerID toSession:self.session withContext:nil timeout:10];
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
NSLog(#"client: lost server: %#", peerID);
}
#pragma mark - MCSessionDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
NSLog(#"client: status changed to %d for server: %#", state, peerID.displayName);
switch (state) {
case MCSessionStateNotConnected: {
}
break;
case MCSessionStateConnected: {
}
break;
default:
break;
}
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSLog(#"client: received data (len = %lu) from server %#",(unsigned long)[data length], peerID.displayName);
NSDictionary *receiveDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
Server:
- (id)init {
self = [super init];
if (self) {
NSString *peerName = [NSString stringWithFormat:#"%#-%#", #"Server", [[UIDevice currentDevice] identifierForVendor].UUIDString];
self.myPeerID = [[MCPeerID alloc] initWithDisplayName:peerName];
self.session = [[MCSession alloc] initWithPeer:self.myPeerID];
self.session.delegate = self;
self.advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.myPeerID
discoveryInfo:nil
serviceType:#"Connect"];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];
}
return self;
}
#pragma mark - MCNearbyServiceAdvertiserDelegate
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler {
NSLog(#"server: did receive invitation from peer %#", peerID.displayName);
invitationHandler(YES, self.session);
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error {
NSLog(#"server: error %#", error);
}
#pragma mark - MCSessionDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
NSLog(#"server: status changed to %ld for client: %#", state, peerID.displayName);
switch (state) {
case MCSessionStateConnected: {
NSMutableDictionary *sendDict = [NSMutableDictionary dictionary];
NSError *error = nil;
[self.session sendData:[NSKeyedArchiver archivedDataWithRootObject:sendDict]
toPeers:#[peerID]
withMode:MCSessionSendDataReliable
error:&error];
}
break;
case MCSessionStateNotConnected:
break;
default:
break;
}
NSLog(#"connectedPeers %#", self.session.connectedPeers);
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSLog(#"server: received data (len = %lu) from client %#", (unsigned long)[data length], peerID.displayName);
NSDictionary *dictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID {
}
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress {
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error {
}
- (void)session:(MCSession*)session didReceiveCertificate:(NSArray*)certificate fromPeer:(MCPeerID*)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler {
certificateHandler(YES);
}

Resources