Game Center not asking my TestFlight users to log in? - testflight

In my app, I use the following code in the view controller in my sprite kit project to authenticate a player using GameKit:
-(void)autheticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (error != nil){
NSLog(#"%#", [error localizedDescription]);
}
if (viewController != nil){
[self presentViewController:viewController animated:YES completion:nil];
}else{
if ([GKLocalPlayer localPlayer].authenticated){
_gameCenterEnabled = YES;
[[GKLocalPlayer localPlayer]loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil){
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
NSLog(#"game center not available");
}
}
};
}
It works fine on my phone, but after building an Ad-Hoc build with a provisioning profile including a friend's phone to see how it would work, they were not asked to log in when they opened the app, whereas my phone was (and all simulator phones were).
On top of that, attempting to open the leaderboards would simply show a message "game center is not available, user is not logged in" or something like that.
I went to this friend's phone's Game Center settings, and verified that sandbox mode was ON. After that, I manually logged in to a Sandbox tester account I made in iTunes connect, and once I opened my app again, (on their phone), it displayed the "welcome back" message. However, the leaderboards showed "no scores", when I believe that my score should be on there.
My questions are:
1. Why were they not asked to log in? Is it a problem with my code, or is that how it's supposed to work when beta testing with sandbox mode on?
2. Why doesn't it show the other scores? My leaderboard is in iTunes connect, and the leaderboard name is properly displayed in the app, but no score are visible.
Thanks for any help!

Apparently, it takes about 10 hours before the other user's scores will be updated. Today, all of my test users' scores are on game center. Would be nice if this was made more obvious, so developers didn't think Game Center wasn't working.

Related

SoundCloud OSX Oauth process doesn't create account unless cancelled

I've been trying to use the CocoaSoundCloudAPI to create a basic desktop app for OSX in Cocoa.
I'm struggling with authentication. Clicking a login button opens up an external browser window that tries to give my app authentication. If I click "Connect" the connect button shows a lovely animation... forever, and [SCSoundCloud account] is null.
However, if I click "Cancel" in the external browser window during this process, I see that SCAccount becomes !nil
Can anyone explain this?
Here's my code:
#import "SCMAppDelegate.h"
#implementation SCMAppDelegate
+ (void)initialize
{
[SCSoundCloud setClientID:#"MYID"
secret:#"MYSECRET"
redirectURL:[NSURL URLWithString:#"sampleproject1://oauth"]];
}
- (IBAction)login:(id)sender
{
[SCSoundCloud requestAccessWithPreparedAuthorizationURLHandler:^(NSURL *preparedURL){
// Load the URL in a web view or open it in an external browser
[[NSWorkspace sharedWorkspace] openURL:preparedURL];
}];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
{
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
andSelector:#selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
withReplyEvent:(NSAppleEventDescriptor*)replyEvent;
{
NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
BOOL handled = [SCSoundCloud handleRedirectURL:[NSURL URLWithString:url]];
if (!handled) {
NSLog(#"The URL (%#) could not be handled by the SoundCloud API. Maybe you want to do something with it.", url);
}
NSLog(#"This is the account: %#", [SCSoundCloud account]);
}
#end
I've been using https://github.com/soundcloud/CocoaSoundCloudAPI/blob/master/GeneralUsage.md as a guide, and have found most things to work. Can anyone push me in the right direction?
I did some NSLogging and found that, in fact, I was receiving a valid SoundCloud Account object, it just needed some more time to receive the object back.
I was, however, surprised that my external browser window never received a notification to indicate that connection had completed - is this an error on my behalf or a regular occurrence when it comes to external oauth2 requests?
It seems that, even if I use Facebook authorisation with my app, I never get notified in the browser page that authentication has completed. Does anyone know how I can achieve this? I'm quite sure that my callback url is correct, but I'll keep trying...

SKPaymentTransactionStateFailed, but no NSError

We have an app with IAP coin purchases. We've recently received mails from a few of our users, saying that they couldn't purchase any coins. I looked at their session logs and saw Failed IAP events, each with no fail reason logged. Here's the related code:
- (void)_purchaseRequestFailed:(SKPaymentTransaction *)transaction state:(StoreTransactionState)state error:(NSError *)error
{
IAPProduct *product = [self getProductWithId:transaction.payment.productIdentifier];
if (error.code==SKErrorPaymentCancelled) {
[_metricsManager logFailIAP:product failReason:#"Payment canceled"];
} else {
[_metricsManager logFailIAP:product failReason:error.localizedDescription];
}
if ([_delegate respondsToSelector:#selector(didSucceedPurchasingProduct:)]) {
[_delegate didFailPurchasingProduct:product];
}
}
inside logFailIAP, I log things like time, UDID, event name, and the error.localizedDescription.
if (failReason != nil && failReason.length > 0) {
[metricsDictionary setObject:failReason forKey:MetricsEventParameterFailReason];
}
In the logs, I'm getting Failed IAP events, but no logged reason for failing. Is there any case where, you get "SKPaymentTransactionStateFailed", but, have an empty error.localizedDescription? I can confirm that the logs work, and have seen errors like "Payment canceled", and "Cannot connect to iTunes" being logged in other devices. The issue is not specific to a device or iOS.
I have encountered a nil error in the following scenario:
User updates iOS on their device.
Immediately after the update, the user goes into your app and tries to make a purchase.
Instead of the usual purchase dialog, they get an "iTunes terms of service have changed. You need to accept new T&C's" (or something along the lines), which redirects them to the iTunes app and shows them the new T&C's. The payment is then cancelled and you get a nil error, and, obviously, a nil error.localizedDescription.
For this scenario to happen, your app needs to be the user's first point of interaction with the iTunes Store after the system update.

GameKit Match - invite friends between iOS5 and iOS6

I'm trying to implement Game Center invites in a 2-person realtime game. Since invites are not supported in the simulator, I'm testing this on one device running iOS5 and a second one running iOS6 (this is done on purpose).
If I'm using the old-fashioned built-in GKMatchmakerViewController UI on either device to initiate the invite, it works fine both ways - when the iOS5 device initiates the invite as well as when the iOS6 device initiates it.
However, in iOS6 I want to use my own UI to select the player to invite, so I'm using GKMatchRequest to programmatically issue the invite, setting the playersToInvite attribute.
The problem is, the other (iOS5) device gets the push notification, launches the application, runs the [GKMatchmaker sharedMatchmaker].inviteHandler, shows the Game Center UI with the invite details, but even when the iOS6 device sends a finishMatchmakingForMatch request - the iOS5 device doesn't proceed any further. No other handler / delegate is called on the iOS5 machine, no GKMatch object is returned, and it continues to show the Game Center UI with both players marked as "Ready" and with a message saying "Waiting for [iOS6 player] to start the game". The only button on this UI is a Cancel button.
Here's the code snippet that sends the invitation on the iOS6 machine:
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = [NSArray arrayWithObject:playerID];
request.inviteMessage = message;
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response)
{
if (response == GKInviteeResponseAccepted)
[[GKMatchmaker sharedMatchmaker] finishMatchmakingForMatch:self.match];
};
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error)
{
... [whatever]
}];
And here's the code snippet for the invite handler on the iOS5 machine:
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite)
{
if (acceptedInvite)
{
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite] autorelease];
mmvc.matchmakerDelegate = self;
[navController presentModalViewController:mmvc animated:YES];
});
else if (playersToInvite)
{
... [whatever]
}
}
The sequence is as follows:
iOS6 sends a findMatchForRequest request with the iOS5 player id.
A push notification is shown on the iOS5 machine.
The application is launched on the iOS5 machine and the inviteHandler is called.
The GKMatchmakerViewController is shown on the iOS5 machine with the invite details, and the iOS6 user has a spinning "Connecting" status.
The inviteeResponseHandler on the iOS6 machine is called and sends a finishMatchmakingForMatch request.
The status of the iOS6 user in the iOS5 Game Center screen changes from spinning "Connecting" to "Ready", and at this point both players are marked as "Ready".
The iOS6 machine gets a match: player: didChangeState: callback, showing the iOS5 player as GKPlayerStateConnected, so as far as the iOS6 machine is concerned the match process is finished and the game can begin.
Nothing whatsoever happens from now on on the iOS5 machine. It is stuck with "Waiting for [iOS6 user] to start the game" until it is cancelled by a timeout. It never receives any GKMatch object at any point, so it cannot start the game.
Since things work fine if I use the standard Game Center UI on the iOS6 machine rather than a programmable invite, it means that the standard UI must do something more to tell the other machine that the game has to start. However, I browsed through all the relevant Game Center objects and couldn't find anything else to send.
I should mention again that the reverse configuration (iOS5 initiating the invite using the standard UI) works fine on both machines.
Help, anyone?
I am having a similar problem. One of the things I did to partially solve is to use programmatic for ios6 users, and viewController for ios5 users. I think you are doing that too but your inviteHandler code only seems to have viewController code. Were you able to fully solve your issue?

How to give an app access to Accounts that was previously denied?

I've been playing with Accounts framework and during my tests I've denied the app access to Accounts. Now the following code returns Denied each time I run it.
[[self accountStore] requestAccessToAccountsWithType:twitterType options:nil completion:^(BOOL granted, NSError *error) {
if (granted) {
accounts = [[self accountStore] accountsWithAccountType:twitterType];
} else if (error != nil) {
NSLog(#"Failed to list Twitter accounts %#", error);
} else {
NSLog(#"Access denied");
}
}];
What sucks is I have no clue where to reset it and googling doesn't help. I've seen how to fix it on iOS but I'm running a Mac app and the solution doesn't apply.
The Account Framework API documentation is not helpful at all.
Palm face.
Figured it out, I've found a file with my app id called "~/Library//Application Support/com.apple.TCC/TCC.db"
It's a sqlite3 file, so run sqlite3 "~/Library//Application Support/com.apple.TCC/TCC.db" then search for your app in "access" table, delete the row and should you have access again.
If that doesn't help there's also a file called ~/Library/Accounts/Accounts3.sqlite, there ZAUTHORIZATION table which includes your app.
The proposed solution no longer works, because of high-profile hacks made by big companies and others. This solution has never been supported and is an invitation to hackers. The right way to do this is using the tool provided by Apple: tccutil.
Thus, do the following:
Open Terminal.
Run tccutil reset <service> [bundle_id], in which <service> can be AddressBook or Calendar or All with the optional ID of the bundle you want to reset.
Example:
tccutil reset All com.apple.Terminal

How to force NSArrayController to reload MOC contents to reflect latest fresh data

I am working on a Mac & iOS App, with iCloud CoreData in between to synchronize the data.
When I update some thing from iOS App, and the updates are already migrated to the PersistentStore in Mac App while the Mac App is running. The problem is I cannot find an effective way to force the NSArrayController to reload all data from the store.
tried -(void) fetch:(id)sender; only can see the delete or added entity, but the updated model property not refreshed...
Please help. Thanks
If you see the latest data in the managed object context, but not in the array controller, you want:
[_yourManagedObjectContext processPendingChanges];
[_yourArrayController fetchWithRequest:nil merge:YES error:&error];
[_yourArrayController rearrangeObjects];
I use this in a Mac/iOS iCloud app to update the Mac app's data when the iCloud store changes.
Following is the reply from Apple's Developer Technical support. It worked for me. Thanks all for providing solutions.
For the OS X app, when reloadFetchResults is called, you can ask the NSManagedObjectContext to reset itself and perform the fetch again.
- (void)reloadFetchedResults:(NSNotification *)note
{
NSDictionary *userInfoDict = [note userInfo];
NSManagedObjectContext *moc = self.coreDataController.mainThreadContext;
// this only works if you used NSMainQueueConcurrencyType
// otherwise use a dispatch_async back to the main thread yourself
//
[moc performBlock:^{
[self mergeiCloudChanges:userInfoDict forContext:moc];
[moc reset];
[self.tableArrayController fetch:self];
}];
}
I've found that
[self.managedObjectContext reset];
[myArrayController fetch:self];
forces my NSTableView (with NSArrayController) to re-populate and display newly processed NSManagedObjects.
in case someone else finds this...
in my case, I was building the array from user interaction (not Core Data), and then trying to show the tableView when they were done (on the same window)... and of course... seeing nothing!
[arrayController rearrangeObjects];
just before I wanted to show the tableView fixed it for me.

Resources