The Game Center tutorial I was following showed me everything except how to report the scores and achievements to the leaderboards.
This is the score part:
+ (void)reportScore:(Float64) score forIdentifier: (NSString*) identifier {
GKScore* highScore = [[GKScore alloc] initWithLeaderboardIdentifier:#"Tap_Competition_LB"];
highScore.value = score;
[GKScore reportScores:#[highScore] withCompletionHandler:^(NSError *error) {
if (error) {
NSLog(#"Error in reporting scores: %#", error);
}
}];
}
and this is the achievement part:
+ (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier: identifier];
if (achievement)
{
achievement.percentComplete = percent;
achievement.showsCompletionBanner = YES;
if (![[NSUserDefaults standardUserDefaults] boolForKey:identifier]) {
//Tell analytics if you want to
}
NSArray *achievements = #[achievement];
[GKAchievement reportAchievements:achievements withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"Error in reporting achievements: %#", error);
} else {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:identifier];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
}
}
Which are both located in the TCUser file I've created, after the authentication of the local user.
The tutorial I was following gave this line of code for reporting:
[SingletonClassName reportAchievementIdentifier:#"com.companyname.gamename.achievementname" percentComplete:100.0f];
But I don't understand which singleton class to reference. Can anyone help me out and show me how exactly to report a score or achievement?
The Apple documentation didn't help either.
PS This was the tutorial: http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=10844
Related
I'm having an issue finding the source of this crash in my iOS app which has a core data model using iPhone app i am not able to login URl. I am using same code on iOS 7 its working but now I am trying to work on iOS 8.2.Have issue for _block_literal_generic
Block point is below As well check screen shot for block Error:---
[[NetwokManager sharedInstance] loginRequestEmail:userEmail andPassword:userPassword WithResponse:^(id responseObject, NSError *error) { if (!error) {
}
Using code is below:
-(void)sendLoginRequest
{
NSString *userEmail = [[NSUserDefaults standardUserDefaults] objectForKey:#"emailKey"];
NSString *userPassword = [[NSUserDefaults standardUserDefaults] objectForKey:#"passwordKey"];
NSLog(#"Email %#", userEmail);
NSLog(#"Password %#", userPassword);
NSString *mobileNo = [SCUserProfile currentUser].callerid;
NSLog(#"CallerID %#", mobileNo);
[[NetwokManager sharedInstance] loginRequestEmail:userEmail andPassword:userPassword WithResponse:^(id responseObject, NSError *error) {
if (!error) {
NSLog(#"responseString = %#", responseObject);
if (responseObject == nil)
{
NSLog(#"No data from server");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"No data downloaded from server!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alertView show];
}
NSDictionary *resposneDict = (NSDictionary*)responseObject;
NSString *success = [resposneDict valueForKey:#"success"];
if ([success isEqual:#"Authentication Failed"])
{
[self showAlertViewWithMessage:#"Authentication Failed"];
// [self sendLogoutRequest];
[[C2CallAppDelegate appDelegate] logoutUser];
}
else if ([success intValue] == 1)
{
amobilePayUserID = [resposneDict valueForKey:#"user_id"];
[[NSUserDefaults standardUserDefaults] setValue:amobilePayUserID forKey:#"AMobilePay_User_ID"];
NSLog(#"User Id is:= %#",amobilePayUserID);
}
else if ([success intValue] == 0)
{
//[self sendRegistrationRequest];
// [self sendLogoutRequest];
// [[C2CallAppDelegate appDelegate] logoutUser];
}
else
{
[self showAlertViewWithMessage:#"Unable to login AmobilePay"];
}
} else {
[self showAlertViewWithMessage:[error localizedDescription]];
}
}];
}
Crash in unknown region 2015-04-30 09:56:18.390 AmobipayMerchant[337:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MOC2CallEvent costs]: unrecognized selector sent to instance 0x16ef2dd0'
Somewhere in the code, you called costs to an instance of MOC2CallEvent. MOC2CallEvent has no method or property costs, so of course it will crash.
I have already configured all Game Center functions and below code i am using to unlock achievement, which is perfectly working fine.
- (void) unlockAchievementThis:(NSString*)achievementID {
GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:
achievementID];
if (achievement){
achievement.percentComplete = 100;
achievement.showsCompletionBanner = true;
[GKAchievement reportAchievements:#[achievement] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"Error at unlockAchievementThis()");
}
}];
}
}
Now My problem is with incremental achievements. I have another method for few achievements and I want the previous achievement percentage to increase it with a constant.
My game is in cpp and i don't know much ObjC.
I got some code below which i think should help me but i don't know how to use achievementDescriptions to get percentage and add incStep into it and submit it to back game center.
- (void) incrementAchievementThis:(NSString*)achievementID :(NSInteger) incStep
{
NSMutableDictionary *achievementDescriptions = [[NSMutableDictionary alloc] init];
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error) {
if (error != nil) {
NSLog(#"Error getting achievement descriptions: %#", error);
}
for (GKAchievementDescription *achievementDescription in descriptions) {
[achievementDescriptions setObject:achievementDescription forKey:achievementDescription.identifier];
}
}];
Percentages are stored in GKAchievement percentComplete, so you need to load (and update and report) GKAchievements instead of GKAchievementDescriptions.
GKAchievmenentDescriptions are configured in iTunes Connect and are "read-only" from the point of view of your app.
Finally i got output by below code...
- (void) incrementAchievementThis:(NSString*)achievementID :(NSInteger) incStep
{
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{
if (error == nil) {
for (GKAchievement* achievement in achievements) {
if ([achievementID isEqualToString:achievement.identifier]) {
achievement.percentComplete += incStep;
[GKAchievement reportAchievements:#[achievement] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"Error at incrementAchievementThis()");
}
}];
}
}
}
else {
NSLog(#"Error in loading achievements: %#", error);
}
}];
}
I found many tutorials online how to share image on twitter from an iOS app. But i want to know 2 things about social sharing with twitter-
If i post an image on twitter via my app, Can i get image id from twitter in callback method/block? If yes then how?
If i fetch favourites of a user, is the response include text posted with that image? I checked for the same on twitter Rest API doc that there is a text property returned in the response.
Now my question is that if i post some text with image via my iOS app and later make this post favourite in twitter app and now i get my favourites list through twitter rest API in my app, does the text property in the response is same that i posted with my post?
Edit about #1 above:- from SLComposeViewControllerResult docs i found that completion handler return one of
typedef NS_ENUM (NSInteger,
SLComposeViewControllerResult ) {
SLComposeViewControllerResultCancelled,
SLComposeViewControllerResultDone
};
constant so there is no info about image just posted. Am i right? If not please give me some reference about how to get image id please.
Here I have customize alertView,NSLog,etc. You ignore that.
Here is the code to share to twitter by using STTwitter library
- (void)shareToTwitter
{
APP_DELEGATE.navController = self.navigationController;
NSString *strTwitterToken = [[NSUserDefaults standardUserDefaults] objectForKey:#"TwitterToken"];
NSString *strTwitterTokenSecret = [[NSUserDefaults standardUserDefaults] objectForKey:#"TwitterTokenSecret"];
if (strTwitterToken && strTwitterTokenSecret)
{
self.twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey:TwitterConsumerKey consumerSecret:TwitterSecretKey oauthToken:strTwitterToken oauthTokenSecret:strTwitterTokenSecret];
[self.twitter verifyCredentialsWithSuccessBlock:^(NSString *username) {
DLogs(#"Twitter User Name");
[self twitterMediaUpload];
} errorBlock:^(NSError *error) {
DLogs(#"-- error: %#", error);
[AppConstant showAutoDismissAlertWithMessage:[error localizedDescription] onView:self.view];
[self safariLoginTwitter];
}];
}
else
{
[self safariLoginTwitter];
}
}
-(void)safariLoginTwitter
{
// [APP_CONSTANT getNativeTwitterAccountAccessToken:^(id result) {
//
// }];
self.twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey:TwitterConsumerKey
consumerSecret:TwitterSecretKey];
[self.twitter postTokenRequest:^(NSURL *url, NSString *oauthToken) {
DLogs(#"-- url: %#", url);
DLogs(#"-- oauthToken: %#", oauthToken);
[[UIApplication sharedApplication] openURL:url];
} authenticateInsteadOfAuthorize:NO
forceLogin:#(YES)
screenName:nil
oauthCallback:#"myapp://twitter_access_tokens/"
errorBlock:^(NSError *error) {
DLogs(#"-- error: %#", error);
[AppConstant showAutoDismissAlertWithMessage:[error localizedDescription] onView:self.view];
}];
}
- (void)setOAuthToken:(NSString *)token oauthVerifier:(NSString *)verifier {
[self.twitter postAccessTokenRequestWithPIN:verifier successBlock:^(NSString *oauthToken, NSString *oauthTokenSecret, NSString *userID, NSString *screenName) {
DLogs(#"-- screenName: %#", screenName);
/*
At this point, the user can use the API and you can read his access tokens with:
_twitter.oauthAccessToken;
_twitter.oauthAccessTokenSecret;
You can store these tokens (in user default, or in keychain) so that the user doesn't need to authenticate again on next launches.
Next time, just instanciate STTwitter with the class method:
+[STTwitterAPI twitterAPIWithOAuthConsumerKey:consumerSecret:oauthToken:oauthTokenSecret:]
Don't forget to call the -[STTwitter verifyCredentialsWithSuccessBlock:errorBlock:] after that.
*/
[[NSUserDefaults standardUserDefaults] setObject:self.twitter.oauthAccessToken forKey:#"TwitterToken"];
[[NSUserDefaults standardUserDefaults] setObject:self.twitter.oauthAccessToken forKey:#"TwitterTokenSecret"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self twitterMediaUpload];
} errorBlock:^(NSError *error) {
[AppConstant showAutoDismissAlertWithMessage:[error localizedDescription] onView:self.view];
DLogs(#"-- %#", [error localizedDescription]);
}];
}
-(void)twitterMediaUpload
{
// ProfileImageBO *objProfImg = nil;
//
// if ([self.objProfile.arrUserImages count]) {
// objProfImg = [self.objProfile.arrUserImages objectAtIndex:0];
// }
[APP_CONSTANT showLoaderWithTitle:#"posting" onView:self.view];
// NSURL *urlProfImg = [NSURL URLWithString:[objProfImg.imageUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURL *screenshotUrl = [self getScreenshotUrl];
[self.twitter postMediaUpload:screenshotUrl uploadProgressBlock:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {
DLogs(#"uploading");
} successBlock:^(NSDictionary *imageDictionary, NSString *mediaID, NSString *size) {
DLogs(#"imageDictionary = %#, mediaID = %#, size %#",imageDictionary.description,mediaID,size);
[self postToTheTwitterWithMediaId:mediaID];
} errorBlock:^(NSError *error) {
DLogs(#"Error in uploading media, try again ...");
[APP_CONSTANT hideLoader];
[AppConstant showAutoDismissAlertWithMessage:error.localizedDescription onView:self.view];
}];
}
-(void)postToTheTwitterWithMediaId:(NSString *)mediaID
{
NSString *msg = [NSString stringWithFormat:#"Check out My Profile"];
[self.twitter postStatusUpdate:msg inReplyToStatusID:nil mediaIDs:[NSArray arrayWithObject:mediaID] latitude:nil longitude:nil placeID:nil displayCoordinates:nil trimUser:nil successBlock:^(NSDictionary *status) {
DLogs(#"Description %#",status.description);
[self showNotificationToastWithMessage:TwitterPostSuccess];
[APP_CONSTANT hideLoader];
} errorBlock:^(NSError *error) {
DLogs(#"Twitter posting error %#",error.description);
[APP_CONSTANT hideLoader];
[AppConstant showAutoDismissAlertWithMessage:error.localizedDescription onView:self.view];
}];
}
For your second question: Yes, you will get the same text in the response
And This is the code to get favorite list
-(void)getFavListTwitter
{
[self.twitter getFavoritesListWithSuccessBlock:^(NSArray *statuses) {
DLogs(#"%#",statuses.description);
} errorBlock:^(NSError *error) {
DLogs(#"%#",error.description);
}];
}
I released my app yesterday and few units were sold so far. But I figured out that the leaderboard doesn't work properly. I can only see my own score when I'm done with my game. Is there some kind of delay until the leaderboard is updated or is it a problem on my implementation? I'd really appreciate if I have my implementation checked by someone who knows how to do it properly. On a side note, I already configured my leaderboard on itunes-connect and enabled it as well. I'm not sure if GKLocalPlayer's instance method loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) is the right method to use to load the correct leaderboardID. Do I manually have to declare my leaderboard ID on Xcode somewhere with the leaderboardID I created on itunes-connect? because I find it odd that I never get to use it on the actual implementation... I want this error fixed as soon as possible and I need you guys' help. Thanks.
(void)authenticateLocalPlayer {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
NSLog(#"authenticated");
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"here");
NSLog(#"%#", [error description]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
- (void)reportScore:(NSNotification *) notification {
if (_gameCenterEnabled) {
NSDictionary *userInfo = notification.userInfo;
NSNumber *score = [userInfo objectForKey:#"highestScore"];
GKScore *gkscore = [[GKScore alloc]initWithLeaderboardIdentifier:_leaderboardIdentifier];
gkscore.value = [score integerValue];
[GKScore reportScores:#[gkscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
}
- (void)showLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
[self presentViewController:gcViewController animated:YES completion:nil];
}
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
I am trying to upload my scores for my game to Gamecenter, however I cannot write code to do that without getting errors. Also, it says that there is no class method for reportScores:scores. I am not sure how to implement that into the Gamecenter Class.
-(void) reportScore: (int64_t) score forLeaderboardID: #"tap_amateur" identifier
{
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier:#"tap_amateur"];
scoreReporter.value = score;
scoreReporter.context = 0;
NSArray *scores = #[scoreReporter];
[GKLeaderboard reportScores:scores withCompletionHandler:^(NSError *error) {
}];
}
#end
Try changing:
[GKLeaderboard reportScores:scores withCompletionHandler:^(NSError *error) {
}];
to:
[GKLeaderboard reportScoreWithCompletionHandler:
^(NSError* error) {
[self setLastError:error];
BOOL success = (error == nil);
if ([_delegate
respondsToSelector:
#selector(onScoresSubmitted:)]) {
[_delegate onScoresSubmitted:success];
}
}];