I have an turn-based game using GameKit in iOS. Generally, my authentication with Game Center works. My game works and I can for periods of time send moves back and forth. However, relatively frequently but not constantly, when I try to perform an action (e.g., finding a new match) over Game Center it fails with the error:
Error Domain=GKErrorDomain Code=6 "The requested operation could not be completed because local player has not been authenticated." UserInfo={NSLocalizedDescription=The requested operation could not be completed because local player has not been authenticated.}
Yet, the GKLocalPlayer.localPlayer().authenticated = true, both immediately before getting the error and after. After getting this error, the authentication viewController does not get presented and GameKit methods that rely on authentication cease to function (they don't come back to life ). Then, if I send the app to the background and then bring it back to the foreground, the error does not return when I retry the action (without requiring new login and password entry).
According to this similar observation:
GKLocalPlayer authentication not working, but isAuthenticated returns YES (Game Center sandbox)
"1.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"
I am getting this problem on the device, not the simulator, ruling out #2. Could someone help me with #1? I may be naive here, but my iPhone and iPad have the right time and date. Is there something or somewhere else I should be checking and setting?
Then, if this is not the issue, what else could be the problem? I am running iOS9.
I've seen this too, and have an open bug with Apple. In my case, I'm testing with multiple physical devices, and only one of those devices ever encounters this. On that particular device, I'm logged into iTunes using a personal account, but logged into game center using a test account.
From what I can see, when the device is using the same login for iTunes, iCloud and game Center, there are no problems. But, when I try to mix-and-match the accounts for whatever testing I need to do, then I randomly get error 6.
There doesn't seem to be anyway to recover from this, except to have the user re-login into game center. Of course, there's no way to present the login view controller again, so the only option is for the user to leave the game, kill it off, and star up again (which re-starts the game center authentication process). I trap the error now, give the user a message saying Game Center has logged them out, and explain what they need to do about it.
But as I said, when I stopped mixing up credentials on the device, the problem went away.
BTW, on a slightly related topic, I've come to view the .authenticated property as completely unreliable. It will be TRUE in conditions where you do not actually have connection to Game Center. I opened a bug on this, too. Apple closed it saying this was working as intended by using "cached" data. Thus, it will report authenticated when it's not authenticated and give you access only to outdated match and leaderboard data which had previously been saved locally.
Related
In our iOS app, in-App purchase(auto-renewable subscriptions) was working very well, but from January this year due to some unknown reason in-App purchase getting failed for European Customers mainly from country "Denmark".
For "Strong customer authentication transactions in European Economic Area" , Now users are moved to outside of the App for Strong Authentication as per new European law (ref: https://developer.apple.com/support/psd2/) and then need to enter NemID etc. and when the User is moving back to the App, I'm getting this error
A. “Purchase failed“ . B. The action could not be performed. C.
SKErrorDomain error 0.
One thing to mention as I'm using SwiftyStoreKit POD for in-App purchase, and Transaction observer is already added in AppDelegate by calling SwiftyStoreKit.CompleteTransaction(atomically: true) as suggested by Apple(Transaction Observer).
#sca(Strong Customer Authentication) #EuropeanUnionregulation
If anyone faced same issue, any help would be great.
Here is the transaction failed screenshot after moving back to my app from strong authentication process:
Indeed since January in Europe they're is a new regulation regarding to transaction security. You can find more details there : https://developer.apple.com/support/psd2/
Lot of apps undergo the same problem. Indeed, even if the documentation says that the transaction observer may receive a "failed" or "deferred" state we can expect that failed state will be only for iOS version that doesn't support the "deferred" state (so iOS versions <=7). Indeed the deferred state case is available since iOS 8.0.
However in reality even on iOS 14 the app transaction observer receive a failed state which results in an error pop-up displayed by a lot of app when they do the error management. Even if at the end the purchase succeed once user come back to the app (after validated the transaction with his bank app), it would be FAR better if iOS can return a "deferred" state to avoid an error pop-up while keeping the error management. And it will be more consistent with what it's happening.
In fact once the security process is completed your app's transaction observer must immediately receive a new transaction with a state purchased so in finality everything should be okay but with an unexpected error pop-up displayed for no real reason.
The only choice we have is let the error be displayed awaiting the end of process or discard the error management. I think the first choice is better and if an iOS version update the statement received it will be going fine without any app update.
Is a valid, even in case of an authentication error?
GKLocalPlayer.localPlayer.authenticateHandler =
^(UIViewController *viewController, NSError *error)
{
if (error)
{
bool a = GKLocalPlayer.localPlayer.authenticated;
}
else
{
This happens for instance when I have an authenticated player, moves the app to the background, disables the WiFi, and then move the app to foreground again. My hope is that GameCenter just continues with a cached account?
I find the manual a bit ambiguous.
From https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/Users/Users.html#//apple_ref/doc/uid/TP40008304-CH8-SW11:
"As soon as your game moves to the background, the value of the local player object’s authenticated property becomes and remains invalid until your game moves back to the foreground. You cannot read the value to determine if the player is still authenticated until Game Kit reauthenticates the player and calls your authentication handler. Your game must act as though there is not an authenticated player until your completion handler is called. Once your handler is called, value stored in the authenticated property is valid again."
Is the value valid even though the authentication failed?
I have a long-running Bug with Apple on this. It's been closed and re-opened during the ongoing dialog. The question of whether or not .authenticated is valid seems to depend on your perspective
Apple views this as working-as-intended as you have cached information which Apple believes lets you go ahead and play your game, you can display leaderboards, etc. Apple says that .authenticated is indeed valid in this state. I've seen some developers on this forum agree with that perspective, although I don't have links handy to their posts.
In practice, though, if you attempt to do any subsequent game center operation while in this state, it will fail because you're not really authenticated. You can't save games, load matches, etc. Any leaderboard you display will be stale, cached data.
It appears to me that Apple loathes for players to ever see a problem resulting from their infrastructure. Thus, with this mechanism you attempt to drive forward by faking the state, hoping the problem works itself out later. In my games, that strategy never pans out and eventually reaches an unrecoverable situation after users have invested time/effort into the game. So, like your code above, I rely on what the NSError says. If is says "error" then I treat the player as unathenticated, providing UI prompts to correct the situation.
I've documented more details on my approach here: https://stackoverflow.com/a/37216566/1641444
So we have a notification screen where users can customize the push notifications they want to receive. In this view controller, we check if [application isRegisteredForRemoteNotifications], we allow users to use the screen, else we show them the prompt that deep links to settings for the app. Now, what's happing is that certain users are complaining that this prompt never disappears even when they turn on in settings. They have sent us the screenshot of the screen, as well as device settings for the app. We have not been able to reproduce this issue. The view controller is directly checking against the OS flag, so there is not much scope of error there. Also we have gone through the code and haven't found anything. I am assuming that because of network issues, deviceToken is not getting delivered to the app. Not really sure what else might be going here. Appreciate any help or suggestions on this matter.
i've met a problem when integrating my game with Facebook Unity SDK, the latest version, on IOS7, IPhone-4s.
Each time the game requests a Facebook login operation, game will become inactive and turns into background, and a Facebook login page appears, then IOS will killed my game, even the memory used by that game is only 90M or so. After login completed, IOS re-launched game, at which time Facebook SDK couldn't find the previous game process who performed the login operation and thus the login result could not be passed into new game instance.
So, there are two questions:
1) Is there any way to make game process alive in background? I have no idea why 90M memory usage is large enough that IOS want to kill my process.
2) Is there any way let the new game process get login result performed by the previous game process?
3) Is there any way to open embedded webView login dialog of Facebook in unity when performs a login operation instead of jumping out my game?
thanks you.
------------ UPDATE ----------
Solution found for the 3rd question:
1) Locating Facebook/Editor/iOS/FbUnityInterface.mm
2) Find method -(void)login:(const char *)scope { ... }
3) change
openWithBehavior:FBSessionLoginBehaviorWithFallbackToWebView
to
openWithBehavior:FBSessionLoginBehaviorForcingWebView
4) now, each time you request login, an embed web-view dialog will be popped out instead of jumping out of current game to Facebook login dialog.
1) First of all make sure that you haven't checked 'PlayerSettings | Other Settings | Configuration | Exit on suspend' option, which kills your app when you leave it.
90MB on iPhone4S could be quite a lot, the device itself has only 512 MB RAM memory, where system takes a lot. If you have many apps open, then your app, then facebook app which nowadays is not lightweight as well, then the biggest active process (your game) could be killed.
2) Yes there is. Facebook Unity3d plugin has a method for checking the logged status, which should return true after succesfull login (even if the app was killed).
if( FB.IsLoggedIn )
{
// your code here
}
3) There is no easy way to do that with current version of Unity3D Facebook plugin.
Try making a debug build in Xcode and see what it says when the application is killed in the background. It should give a stacktrace to see what happens. That 90MB shouldn't be a problem for an iPhone4S so out of memory crash could be ruled out.
In just about every example of submitting achievements to Game Center, I see this code
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
// Retain the achievement object and try again later (not shown).
}
}];
Problem is, that one little comment is about 99% of the work. I've spent the last few hours trying to figure this out and it seems to be an endless set of edge cases of sending and resending and save and loading data.
Does anyone know of a nice tutorial (or sample code) on this that actually explains the hard part?
It's not as simple as just saving them to a file and loading them later. You get into trouble when you start having to retain multiple achievements and submit them later and then they all come back failed (in blocks!) and you have to save them again... quickly/safely... because the App might quit and you don't want to loose them.
I'm pulling my hair out.
I don't think you need to pull your hair out.
I think the basic model is this:
(a) Independent of Game Center, your game has a saved state (which you always need anyway, to restore the player to where he was when your game is quit/backgrounded). This state should include all the normal stuff you need to restore your game state, plus it should include flags for all of the achievements in your game.
(b) Game Center also stores all of the achievements in your game. When you connect to Game Center, you download the signed-in player's achievements. (Complications arise as to who the signed-in player is, but your question is not about that, so let's assume the "one true player" is always the signed-in Game Center player.)
(c) Whenever the player makes an achievement, first update the appropriate achievement flag in your game's saved state data. Second, try to tell Game Center about that achievement. If it works, update your copy of Game Centers achievements with the new data.
(d) If it doesn't work, you have an achievement marked in your persistent state that is not marked in your copy of the Game Center state. At various convenient times (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) check if there are any discrepancies between what is in your own state vs. what is in the Game Center state. A discrepancy is an update that you need to re-send to Game Center. Try to send, but if it fails again, just wait until the next opportunity (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) to try again. You will never lose the data because it's in your local, true picture of the user's state. (The only way you'd lose it is if the user uninstalls your app before you've been able to successfully get it to Game Center, but then, what can you do?)