Failing to authenticate local player iOS6 - iphone

I'm building a Game Center game in iOS6 and am continuously running into problems with it. The current one has me stumped - Every single time my game tries to authenticate the local player it fails. Every time it is triggering my "disable game center" function and it's driving me crazy.
- (void) disableGameCenter
{
// Write something to disable gamecenter.
// gameCenterAvailable = FALSE;
}
-(void)showAuthenticationDialogWhenReasonable:(UIViewController *)viewController
{
// Pause Tasks Here
// [[[(AppDelegate *)[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:viewController animated:YES completion:nil];
}
- (void) authenticateLocalPlayer
{
localPlayer = [GKLocalPlayer localPlayer];
__weak GKLocalPlayer* weakLocalPlayer = localPlayer;
weakLocalPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if (viewController != nil)
{
[self showAuthenticationDialogWhenReasonable: viewController];
}
else if (weakLocalPlayer.isAuthenticated)
{
self.localPlayer = weakLocalPlayer;
}
else
{
[self disableGameCenter];
}
};
}

Forgive me if I'm wrong, but I don't think you are running the authenticate method.
Try this method instead:
- (void) authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated)
{
NSLog(#"Authenticated");
}
else
{
NSLog(#"Not Authenticated");
}
}];
}

Related

Facebook Dialog showing only in Portrait mode

I have a issue with the Login and sharing dialogs on my app. About a week ago they started appearing only on Portrait mode (either normal or upside down), but the landscape modes does not work.
NSArray *permissions = #[#"user_photos",
#"user_likes",
#"user_friends",
#"email"];
_loginManager = [[FBSDKLoginManager alloc] init];
_loginManager.loginBehavior = FBSDKLoginBehaviorWeb;
[_loginManager logInWithReadPermissions:permissions fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if(result.isCancelled || error)
{
[self pressedCancel];
return;
}
NSSet* declinedPermissions = result.declinedPermissions;
for (NSString *declinedPermission in declinedPermissions) {
if(!nullOrEmpty(declinedPermission))
{
[self pressedCancel];
return;
}
}
if ([FBSDKAccessToken currentAccessToken]) {
// self.settings.facebookToken = [FBSDKAccessToken currentAccessToken].tokenString;
// Send data capture
if([EventData sharedInstance].dataCaptureSettings.enabled)
{
[FacebookHelper getUserInfoWithCompletion:
^(NSDictionary* userInfo, NSError* error)
{
if(!nullOrEmpty(userInfo))
{
[self captureData:userInfo];
} else {
[self captureData:nil];
}
[self didSignIn];
}];
return;
} else {
[self captureData:nil];
[self didSignIn];
}
}
}];
Here's a MPOC to replicate the issue:
https://www.dropbox.com/s/p62vajqfk916bz1/FBTest.zip?dl=0
Any ideas what may be causing this? Or how could I make it work on Landscape mode as well?
Thanks!
just in case anyone else has this issue, it was fixed on the newest Facebook SDK for iOS (4.38.1)

Handle ACAccountStoreDidChangeNotification for Facebook & Twitter in iOS 6+

I am using Social framework for Facebook & Twitter integration. For this I followed this link
Everything is working fine except when I app receives ACAccountStoreDidChangeNotification , it crashes.
App crashes when
1) I installed app for first time & user don't have Facebook / Twitter account configured in Settings.
2) When I call any method of Facebook / Twitter , it gives me error code 6 as I don't have account configured which is right.
3) I click on HOME button so my app enters background & add account in Settigs.
4) Once I configured account & come back to app , my app launches from background & receives ACAccountStoreDidChangeNotification.
5) In selector of ACAccountStoreDidChangeNotification my account object is nil so my app crashes. So I checked for the nil
Here is my code
#pragma mark - Request Facebook Account Access
-(void)requestFacebookAccountAccess
{
requestType = kNoOpRequest;
// Register for Account Change notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(accountChanged:) name:ACAccountStoreDidChangeNotification object:nil];
self.accountStore = [[ACAccountStore alloc]init];
ACAccountType *FBaccountType= [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Set facebook permissions
NSArray *permissions = nil;
// We need to ask for Basic permission first
if (![kUserDefaults boolForKey:FACEBOOK_BASIC_PERMISSION]) {
permissions = #[#"email",#"user_about_me",#"user_location",#"friends_about_me"];
self.isBasicFacebookPermissionsRequested = YES;
}
else {
permissions = #[#"email",#"user_about_me",#"user_location",#"friends_about_me",#"publish_stream"];
}
//use ACAccountStore to help create your dictionary
NSDictionary *dictFacebook = #{
ACFacebookAppIdKey: kFacebookAppIDKey,
ACFacebookPermissionsKey: permissions,
ACFacebookAudienceKey: ACFacebookAudienceFriends
};
[self.accountStore requestAccessToAccountsWithType:FBaccountType options:dictFacebook completion:^(BOOL granted, NSError *error) {
if (granted) {
if (self.isBasicFacebookPermissionsRequested) {
self.isBasicFacebookPermissionsRequested = NO;
[kUserDefaults saveBasicFacebookPermissionsGrantedStatus:YES];
//[self requestFacebookAccountAccess];
}
// User granted permission to Accout
NSArray *accountsArray = [self.accountStore accountsWithAccountType:FBaccountType];
if ([accountsArray count]>0) {
//It will always be the last object with SSO
self.facebookAccount = [accountsArray lastObject];
NSLog(#"In %s::IS MAIN THREAD:- %#",__PRETTY_FUNCTION__,[NSThread isMainThread]?#"YES":#"NO");
if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessGranted)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessGranted];
});
}
}
else {
[self showAlertWithTitle:#"Error" andMessage:#"You don't have any Facebook accounts set up yet.Please set a Facebbok account and try again."];
}
}
else {
DLog(#"User denied permission to Accout::Localized Error:- %#",error.localizedDescription);
if([error code]==6) {
[self showAlertWithTitle:#"Error" andMessage:#"Please setup facebook account from Settings"];
if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessDenied:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessDenied:error];
});
}
}
else if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessDenied:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessDenied:error];
});
}
else {
// User denied permission to Account
[self showAlertWithTitle:#"Error" andMessage:[NSString stringWithFormat:#"User denied permission to Accout::Error:- %#",error.localizedDescription]];
}
}
}];
}
#pragma mark - Get Logged In User Info
-(void)getLoggedInUserInfo
{
NSURL *requestURL = [NSURL URLWithString:#"https://graph.facebook.com/fql"];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"SELECT current_location,uid,name,sex,birthday,email,pic FROM user WHERE uid=me()",#"q", nil];
requestType = kGetLoggedInUserInfoRequest;
[self requestDataUsingURL:requestURL parameters:dict requestMethod:SLRequestMethodGET];
}
#pragma mark - Request Data From Facebook
-(void)requestDataUsingURL:(NSURL*)requestURL parameters:(NSDictionary*)params requestMethod:(SLRequestMethod)reuqestMethod
{
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook
requestMethod:reuqestMethod
URL:requestURL
parameters:params];
request.account = self.facebookAccount;
[request performRequestWithHandler:^(NSData *data,
NSHTTPURLResponse *response,
NSError *error)
{
NSDictionary *dictData =[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if(!error)
{
if([dictData objectForKey:#"error"]!=nil)
{
DLog(#"Request Data From Facebook Errro:- %#",dictData);
[self attemptRenewCredentials];
if ([self.delegate respondsToSelector:#selector(didGetFacebookError:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didGetFacebookError:dictData];
});
}
}
else {
// Process the response
//NSLog(#"Response Dictionary contains: %#", dictData );
if ([self.delegate respondsToSelector:#selector(didPostToFacebook:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didPostToFacebook:dictData];
});
}
}
}
else{
if ([self.delegate respondsToSelector:#selector(didGetFacebookError:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didGetFacebookError:dictData];
});
}
else {
[self showAlertWithTitle:#"Error" andMessage:#"Some error occured while processing Facebook request"];
}
}
}];
}
-(void)accountChanged:(NSNotification *)notif
{
if (self.facebookAccount!=nil) {
[self attemptRenewCredentials];
}
else {
[self requestFacebookAccountAccess];
}
}
#pragma mark - Attempt to Renew Credentials
-(void)attemptRenewCredentials
{
[self.accountStore renewCredentialsForAccount:(ACAccount *)self.facebookAccount completion:^(ACAccountCredentialRenewResult renewResult, NSError *error){
if(!error)
{
switch (renewResult) {
case ACAccountCredentialRenewResultRenewed:
NSLog(#"Good to go");
[self againRequestFacebook];
break;
case ACAccountCredentialRenewResultRejected:
NSLog(#"User declined permission");
break;
case ACAccountCredentialRenewResultFailed:
NSLog(#"non-user-initiated cancel, you may attempt to retry");
break;
default:
break;
}
}
else{
//handle error gracefully
NSLog(#"error from renew credentials%#",error);
}
}];
}
-(void)againRequestFacebook
{
switch (requestType) {
case kGetLoggedInUserInfoRequest:
[self getLoggedInUserInfo];
break;
case kGetFriendsInfoRequest:
[self getFacebookFriendsInfo];
break;
case kPostToWallRequest:
[self postToFacebookWallInBackgroundForUserId:fbUserIdForPost withParams:paramsToPost];
break;
default:
break;
}
}
#pragma mark - Remove Observer for Notification
-(void)dealloc
{
requestType = kNoOpRequest;
[[NSNotificationCenter defaultCenter] removeObserver:ACAccountStoreDidChangeNotification];
}
But accountChanged method gets called multiple times.
What is wrong in this ? How can I handle this situation ?
Any kind of help is highly appreciated.
Thanks in advance.
I am facing the same problem...so i used a work around by having a BOOL value in NSUserDefaults to execute accountChanged method only once
-(void)accountChanged:(NSNotification *)notif
{
BOOL calledAccountChanged =[[[NSUserDefaults standardUserDefaults] objectForKey:DidAccountChanged] boolValue];
if(!calledAccountChanged)
{
if (self.facebookAccount!=nil) {
[self attemptRenewCredentials];
}
else {
[self requestFacebookAccountAccess];
}
}
}
Then we can change DidAccountChanged value later in the code...
If you have better solution do post it...

How to deal with game center invitations, if the friend has not progressed far enough in the app to reach the installInvitationHandler method?

I'm creating a real time matches game and I'm confused as to how to deal with game invitations? For instance, a player on one device can invite his friends to a match and then an invitation banner will appear on the friends' devices. They can tap on the banner and accept the invitation. Now, this works fine if the friend has run the app before and has installed the below invitation handler (installed in the 2nd view controller of the app)
- (void) installInvitationHandler
{
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
// Insert game-specific code here to clean up any game in progress.
if (acceptedInvite)
{
if(self.myConnectingVC) return;
else if(self.myMatchmakerVC)
{
[self dismissViewControllerAnimated:YES completion:^{
self.myMatchmakerVC = nil;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite];
mmvc.matchmakerDelegate = self;
self.myConnectingVC = mmvc;
[self presentViewController:mmvc animated:YES completion:nil];
}];
}
else
{
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
}
else if (playersToInvite)
{
[self createMatchWithPlayersToInvite:playersToInvite];
}
};
}
The problem is, what do I do if the friend has never run the app before or if the friend has not progressed far enough in the app to reach the installInvitationHandler method? If this happens, if the friend taps on the invitation banner, the app will open but it will not accept the invitation.
You should add the inviteHandler immediately after your app launches. The GKInvite object is passed in when the handler is called.
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
//By the time this block is called, you have already received the
//invite, it's passed as a parameter
if (acceptedInvite) {
//This is your invite
} else if (playersToInvite) {
//The player has launched your app from the Game Center app, invite these players.
}
};
I found it best to attach the inviteHandler as a completion block to the authenticateHandler of GKLocalPlayer.
This is for iOS 6.0 onwards...
[GKLocalPlayer localPlayer].authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if([GKLocalPlayer localPlayer].authenticated)
_gameCenterFeaturesEnabled = YES;
// Present the view controller if needed
if (![GKLocalPlayer localPlayer].authenticated)
{
if(viewController)
[self presentViewController:viewController];
return;
}
if (error)
{
if(completionHandler)
completionHandler(error);
}
else
{
[self authenticationCompleted];
if(completionHandler)
completionHandler(nil);
}
};
With the completion handler being...
if(!error)
{
CCLOG(#"Adding invite handler.");
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
CCLOG(#"Invite recieved.");
// Insert game-specific code here to clean up any game in progress.
if (acceptedInvite)
{
GKMatchmakerViewController *mmvc = [[GameDataCache sharedData].match createWithInvite:acceptedInvite];
mmvc.matchmakerDelegate = [GameDataCache sharedData].match;
}
else if (playersToInvite)
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = playersToInvite;
GKMatchmakerViewController *mmvc = [[GameDataCache sharedData].match createNewRequest:request cancelledBlock:nil];
mmvc.matchmakerDelegate = [GameDataCache sharedData].match;
}
};
}
Pre iOS6 needs to call authenticateWithCompletionHandler on the localPlayer instead of assigning the authenticateHandler property.

How Can i Know if GKAchievement is Completed?

I have built objectives for my game and everything works just fine accept the part of making the objectives not be called any more after any of them is completed.
I know there is a Property of the GKAchievement Class "completed" which is a boolean that returns yes when the Achievement is 100 percent done.
here is the method that called when a Achievement is 100 percent done it passes id which is the Achievement identifier and report the acheeee :
- (void)AchivmentDidAchive:(id)Achivment{
NSString *identifier = Achivment;
NSLog(#"%#",identifier);
self.achivment = [[GKAchievement alloc]initWithIdentifier:identifier];
self.achivment.showsCompletionBanner = YES;
if (!self.achivment.completed) {
self.achivment.percentComplete = 100;
NSLog(#"Reproting!");
[self.achivment reportAchievementWithCompletionHandler: ^(NSError *error)
{
}];
}
else {
NSLog(#"Achivment Completed!");
} }
what I am trying to do here is to set the percent completed to 100 and report it so in the next time ie want get called again.
but it always works... any better idea for how to handle this?
in interface add variable & property:
NSMutableDictionary *earnedAchievementCache;
#property (nonatomic, retain)NSMutableDictionary *earnedAchievementCache;
in .m:
#synthesize earnedAchievementCache;
- (void) submitAchievement: (NSString*) identifier percentComplete: (double) percentComplete
{
if(self.earnedAchievementCache == NULL)
{
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
if(error == NULL)
{
NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement* score in scores)
{
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache= tempCache;
[self submitAchievement: identifier percentComplete: percentComplete];
}
}];
}
else
{
GKAchievement* achievement= [self.earnedAchievementCache objectForKey: identifier];
if(achievement != NULL)
{
if((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete))
{
achievement= NULL;
}
achievement.percentComplete= percentComplete;
}
else
{
achievement= [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
achievement.percentComplete= percentComplete;
[self.earnedAchievementCache setObject: achievement forKey: achievement.identifier];
}
if(achievement!= NULL)
{
//Submit the Achievement...
if (achievement.percentComplete>=100) {
//show banner
achievement.showsCompletionBanner = YES; //only in IOS 5+
}
[achievement reportAchievementWithCompletionHandler: ^(NSError *error)
{
if (error!=NULL){
NSLog(#"Error!!");
} else NSLog(#"all is well");
}];
}
}
}
in dealloc :
[self.earnedAchievementCache release];
i'm using the cache to not submit scores already submitted / completed
PS: the code is perfect just copy and paste it into your class and it will work
this is what I use in my helper Game Center class:
-(void) reportAchievementWithID:(NSString*) AchievementID {
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
if(error) NSLog(#"error");
for (GKAchievement *ach in achievements) {
if([ach.identifier isEqualToString:AchievementID]) { //already submitted
NSLog(#"Already submitted");
return ;
}
}
GKAchievement *achievementToSend = [[GKAchievement alloc] initWithIdentifier:AchievementID];
achievementToSend.percentComplete = 100;
achievementToSend.showsCompletionBanner = YES;
[achievementToSend reportAchievementWithCompletionHandler:NULL];
}];
}
note: I don't use percentages in my achievements, so you'd need to modify things a little bit if you do.

Game Center Friend List

All
I made a game for the Apple iOS. Now I would like to show my friend list in Apple's Game Center.
How can I show the Game Center friend list of a logged in player on an iPhone, possibly using the UIViewController (which manages the ViewControllers)?
Any help would be appreciated..
Thanks...
To show your Game center friends in your app you can use the below code given.
-(void) retrieveFriends
{
GKLocalPlayer *lp = [GKLocalPlayer localPlayer];
if (lp.authenticated)
{
[lp loadFriendsWithCompletionHandler:^(NSArray *friends, NSError *error)
{
if (friends != nil)
{
[self loadPlayerData: friends];
}
}];
}
}
-(void) loadPlayerData: (NSArray *) identifiers
{
[GKPlayer loadPlayersForIdentifiers:identifiers withCompletionHandler:^(NSArray *players, NSError *error)
{
if (error != nil)
{
// Handle the error.
}
if (players != nil)
{
// Process the array of GKPlayer objects.
}
}];
}
For more reference you can use the Apple Game KIT guide. below is the link to it
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Introduction/Introduction.html
Hope it helps..
For a single Block:
-(void)loadPlayerData:(void (^)(NSArray * playerObjects))complete
{
GKLocalPlayer *lp = [GKLocalPlayer localPlayer];
if (lp.authenticated)
{
[lp loadFriendsWithCompletionHandler:^(NSArray *friends, NSError *error)
{
if (friends != nil)
{
[GKPlayer loadPlayersForIdentifiers:friends withCompletionHandler:^(NSArray *players, NSError *error)
{
if (error != nil)
{
// return #[error];
// Handle the error.
}
else
{
complete (players);
}
}];
}
}];
}
}