问题
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?
回答1:
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;
}
}
};
}
回答2:
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);
}
来源:https://stackoverflow.com/questions/23541764/gklocalplayer-authentication-not-working-but-isauthenticated-returns-yes-game