Handle ACAccountStoreDidChangeNotification for Facebook & Twitter in iOS 6+ - facebook

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...

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)

How to get user details using twitter api v1.1 (Twitter error 215)

I have used the twitter api provided by twitter,to get the details but
not able to execute it, even tried to pass the authentication data
like consumer secret key, consumer key, token but the result is same.
I am able to login and receiving twitter authentication token but not able to get user details.
Below code is used by me (I am using MGtwitter engine) :
NSMutableURLRequest *request =[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://api.twitter.com/1.1/users/show.json?screen_name=%#",username]]];
NSData *returnData = [ NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil ];
NSString *returnString = [[NSString alloc]initWithData:returnData encoding:NSUTF8StringEncoding];
NSError *err = nil;
twitterLogin = [NSJSONSerialization JSONObjectWithData:[returnString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&err];
Error is shown as below:
errors = (
{
code = 215;
message = "Bad Authentication data";
} );
First, you need to Authenticate your request (Get permission).
second, see follow these steps:
1.Download FHSTwitterEngine Twitter Library.
2.Add the folder FHSTwitterEngine" to your project and #import "FHSTwitterEngine.h".
3.add SystemConfiguration.framework to your project.
Usage : 1.in the [ViewDidLoad] add the following code.
UIButton *logIn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
logIn.frame = CGRectMake(100, 100, 100, 100);
[logIn setTitle:#"Login" forState:UIControlStateNormal];
[logIn addTarget:self action:#selector(showLoginWindow:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:logIn];
[[FHSTwitterEngine sharedEngine]permanentlySetConsumerKey:#"<consumer_key>" andSecret:#"<consumer_secret>"];
[[FHSTwitterEngine sharedEngine]setDelegate:self];
and don't forget to import the delegate FHSTwitterEngineAccessTokenDelegate.
you need to get the permission for your request, with the following method which will present Login window:
- (void)showLoginWindow:(id)sender {
[[FHSTwitterEngine sharedEngine]showOAuthLoginControllerFromViewController:self withCompletion:^(BOOL success) {
NSLog(success?#"L0L success":#"O noes!!! Loggen faylur!!!");
}];
}
when the Login window is presented, enter your Twitter Username and Password to authenticate your request.
add the following methods to your code:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[FHSTwitterEngine sharedEngine]loadAccessToken];
NSString *username = [[FHSTwitterEngine sharedEngine]loggedInUsername];// self.engine.loggedInUsername;
if (username.length > 0) {
lbl.text = [NSString stringWithFormat:#"Logged in as %#",username];
[self listResults];
} else {
lbl.text = #"You are not logged in.";
}
}
- (void)storeAccessToken:(NSString *)accessToken {
[[NSUserDefaults standardUserDefaults]setObject:accessToken forKey:#"SavedAccessHTTPBody"];
}
- (NSString *)loadAccessToken {
return [[NSUserDefaults standardUserDefaults]objectForKey:#"SavedAccessHTTPBody"];
}
4.Now you are ready to get your request, with the following method(in this method I created a Twitter search for some Hashtag, to get the screen_name for example):
- (void)listResults {
dispatch_async(GCDBackgroundThread, ^{
#autoreleasepool {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// the following line contains a FHSTwitterEngine method wich do the search.
dict = [[FHSTwitterEngine sharedEngine]searchTweetsWithQuery:#"#iOS" count:100 resultType:FHSTwitterEngineResultTypeRecent unil:nil sinceID:nil maxID:nil];
// NSLog(#"%#",dict);
NSArray *results = [dict objectForKey:#"statuses"];
// NSLog(#"array text = %#",results);
for (NSDictionary *item in results) {
NSLog(#"text == %#",[item objectForKey:#"text"]);
NSLog(#"name == %#",[[item objectForKey:#"user"]objectForKey:#"name"]);
NSLog(#"screen name == %#",[[item objectForKey:#"user"]objectForKey:#"screen_name"]);
NSLog(#"pic == %#",[[item objectForKey:#"user"]objectForKey:#"profile_image_url_https"]);
}
dispatch_sync(GCDMainThread, ^{
#autoreleasepool {
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Complete!" message:#"Your list of followers has been fetched" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
});
}
});
}
That's all.
I just got the screen_name from a search Query, you can get a timeline for a user using the following methods:
// statuses/user_timeline
- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count;
- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID;
instead of the search method above.
Note: see the FHSTwitterEngine.h to know what method you need to use.
Note: to get the <consumer_key> and the <consumer_secret> you need to to visit this link
to register your app in Twitter.
Got the solution after MKAlatrash revert, to get the user profile follow certain steps in the code as under :
[[FHSTwitterEngine sharedEngine]getProfileImageForUsername:username andSize:FHSTwitterEngineImageSizeNormal];
jump to definition of this function and replace the if ... else if part
if ([userShowReturn isKindOfClass:[NSError class]]) {
return [NSError errorWithDomain:[(NSError *)userShowReturn domain] code:[(NSError *)userShowReturn code] userInfo:[NSDictionary dictionaryWithObject:request forKey:#"request"]];
NSLog(#"user show return %#",userShowReturn);
} else if ([userShowReturn isKindOfClass:[NSDictionary class]]) {
return userShowReturn;
NSString *url = [userShowReturn objectForKey:#"profile_image_url"]; // normal
if (size == 0) { // mini
url = [url stringByReplacingOccurrencesOfString:#"_normal" withString:#"_mini"];
} else if (size == 2) { // bigger
url = [url stringByReplacingOccurrencesOfString:#"_normal" withString:#"_bigger"];
} else if (size == 3) { // original
url = [url stringByReplacingOccurrencesOfString:#"_normal" withString:#""];
}
id ret = [self sendRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
if ([ret isKindOfClass:[NSData class]]) {
return [UIImage imageWithData:(NSData *)ret];
}
return ret;
}
That really was helpful thanks

Facebook sdk 3.5 requests not working

In Facebook SDK 3.5, I'm trying to send an App Request using the following code
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:#"Join"
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
NSLog(#"request error");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
NSLog(#"request FBWebDialogResultDialogNotCompleted");
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
NSLog(#"request success");
}
else
{
// User Cancelled the dialog
NSLog(#"request cancelled");
}
}
}
];
if i use the above code with the Facebook sample FacebookAppID,URL types,FacebookDisplayName it's working fine.
But if i give my own acebookAppID,URL types,FacebookDisplayName the notifications were not delivered.
Any help appreciated....
I have configured "App on Facebook" and "Native iOS App" configurations in settings, Now the notifications are being delivered to iOS and Web App(facebook).
If the notifications are not being delivered to iOS Goto App--> Edit Settings--> App Details and change the category to games/business according to your need. Now the notifications will be delivered to your Desktop Facebook as well as iOS.
I have tried "Native Android App" configurations as well to deliver my notifications to desktop,iOS and android,but no luck as of now. I think there is a problem with android settings.please let me know if anyone have the answer.
Try this :-
1.>First setup your application on facebook by following Facebook url.
2.> Then use this code and modify according to your requirments.
-(void)inviteFriends
{
if ([[FBSession activeSession] isOpen])
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:#"put your message here"
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}
];
}
else
{
/*
* open a new session with publish permission
*/
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObject:#"publish_stream"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
if (!error && status == FBSessionStateOpen)
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}];
}
else
{
[self requestFailedWithError:error];
}
}];
}
}
Please check your app check permission. If permission not assign then please assign permissions whatever you want in your app
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:/*assign permission here*/ nil];
here are the helper functions that calls delegates function OnFBSuccess and OnFBFailed.
- (void)requestSucceeded
{
NSLog(#"requestSucceeded");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBSuccess");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
- (void)requestFailedWithError:(NSError *)error
{
NSLog(#"requestFailed");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBFailed:");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback setArgument:&error atIndex:2];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
So the class taht calls method InviteFriend MUST have these functions:
-(void)OnFBSuccess
{
CCLOG(#"successful");
// do stuff here
[login release];
}
-(void)OnFBFailed:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
// do stuff here
// [login release];
}
- (void)requestFailedWithError:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
}
i hope it helps you.

Failing to authenticate local player iOS6

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");
}
}];
}

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.