Issues Surrounding GKPlayer's playerId Deprecation in iOS 13

I watched the video on Game Center Player Identifiers and saw that GKPlayer's playerId is deprecated in iOS 13, to be replaced with gamePlayerId and teamPlayerId. https://developer.apple.com/videos/play/wwdc2019/615/


Our games allow players to login with Game Center to join and play games hosted on our servers. We use playerId to identify players so that they can play and earn rating points under their own account. The video says to transition to using teamPlayerId to identify players, which by itself isn't too complicated, but I'm concerned that this hasn't been fully thought through and some players may lose access to their accounts in systems like ours.


1. As player's login during the transition period, we will need to read both playerId and teamPlayerId in order to change their account on our servers to the new id. After the transition, when playerId is removed from iOS, it seems that any player who hasn't logged in, perhaps returning to the app after a long break, will no longer be able to access their previous account. They will appear to us as a completely new player. It seems we need some proactive way, like a server API, to convert playerId values to the new teamPlayerId.


2. In the video, the presenter says that there is a "very rare case" when teamPlayerId and gamePlayerId will not be available to uniquely identify the player. In this case, we will have no method of identifying the player and allowing them to access an account on our servers. Nothing is explained about what this "very rare case" is or how to help users correct this. Slide 13 shows how to check for the error case, but does not provide any example error message or error handling.


3. We use GKLocalPlayer's generateIdentityVerificationSignatureWithCompletionHandler API to authenticate players on our servers. This API has not been updated, and it's documentation still says to use playerId. It seems a new API will be needed to deal with players having multiple, different ids.


I'm interested to hear from other developers who use Game Center as a login method for their own servers and are facing these kinds of issues. I'm hoping this post might get the attention of someone at Apple, but I'll also try to engage them in other ways and report anything I find out.

Replies

+1


We really need updated information about generateIdentityVerificationSignatureWithCompletionHandler

Is there still no way to authenticate a player using the gamePlayerId/teamPlayerId?


We're also using generateIdentityVerificationSignatureWithCompletionHandler and switching to gamePlayerId causes the verification to fail.

I don't know of any way to authenticate with gamePlayerId/teamPlayerId. We're still authenticating only the deprecated playerId, but are sending and storing the new ids, so we'll be prepared for the day when playerId goes away.

Has anyone successfully used GKPlayer.loadPlayers(forIdentifiers: , withCompletionHandler:) using either gamePlayerIDs or teamPlayerIDs for as "forIdentifiers"?


My game happily used loadPlayer() for playerIDs (since deprecated), but I always get an empty GKPlayer array (no error code) from using the function now with gamePlayerIDs or teamPlayerIDs. Build 12.4.

FYI, .playerID is still working in iOS 13, though it likely will stop working in a future version. Perhaps this info is useful to someone.

Here are my findings regarding gamePlayerIDs and teamPlayerIDs:


1. I can get the localPlayer's gamePlayerID and teamPlayerID with no problem. I have never had scopedIDsArePersistent be false. However, for my app the two IDs are the same, for some reason. The teamPlayerID is of the form "T:_<32 hex digits>", whereas the old playerID used to be "G:<10 decimal digits>".


2. I can NOT get the teamPlayerID for an opponent. In a real-time match, [myGKMatch.players objectAtIndex:0].scopedIDsArePersistent is always false. If I attempt to read the teamPlayerID field anyway, I get a 16 digit hex string (with no "T:_" prefix), and this string doesn't ever appear to be the same string twice, even for the same opponent. I also tried this with a turn-based match, where I found the opponent's GKPlayer through a GKTurnBasedParticipant array, with the same results.


I don't know if we are supposed to be able to get the teamPlayerID of an opponent, but this always used to work for playerIDs.

We put some analytics in our apps that track the return values of scopedIDsArePersistent for the local player, and we are seeing a small percentage of players on iOS 13 where the value is false, as Apple said to expect. Once playerId is gone, I'm still not sure how we're supposed to identify these users on our servers. On iOS 12.4, scopedIDsArePersistent was not available, but we have still seen users where the game/team player ids have changed. As a result, we have users accounts in our system that have a single "G:" or "U:" playerId value, but multiple "A:" and "T:" values. I went ahead and filed a bug report for this (FB7137603). We're also seeing another bug where occassionally we receive the values "UnknownID" and "Unavailable Player Identification" for the game/team player ids (FB7137454), so we're ignoring those values now. Coinciding with the public release of iOS 13.0, we also started receiving some empty string values for game/team player ids.

  • Did you get any response from Apple on the reported bugs? Especially FB7137454, I am experiencing the same issues with "UnknownID".

Add a Comment

Thanks, this is good info. I'm testing in a non-production environment, so I don't have many data points.

Just another +1, particularly with regards to an updated generateIdentityVerificationSignature method.


In addition, I'd add that watchOS does not support gamePlayerID or teamPlayerID, making the only option on that platform deprecated.

Hello everyone. I am new here. Thanks for the useful information 😉

Obviously relevant at the moment.


I'm attempting to finalize my first Game Center game after years of watching the APIs, and I'm not succeeding in finding out how to use the new scoped IDs while avoiding playerID entirely. For example, I can't see there's even one available pattern for obtaining scoped identifiers for the local player's Game Center friends in order to invite them to a match. Meanwhile, the existing methods for this pattern – obtaining and using a playerID to form a match request – appear to have been deprecated as well.


I get the feeling WWDC 2020 is going to bring a wave of clarity along with some of this seemingly unreplaced functionality, and that the video presentation about the scoped identifiers are more of a sneak peek than a true call for conversion to what will replace it. But that's entirely inference, and that clarity seems merited at the mention of these new APIs and deprecations.

I decided to keep using playerID for now, and to stash away a mapping between that and gamePlayerID/teamPlayerID when scopedIDsArePersistent indicates that those are not transient. I'll figure out how to transition data associated with playerID when/if clarity is provided.

Agreed – I think for now I just have to proceed as though the scoped IDs weren't announced yet.

Okay, I'm working things out. As seems to be the case with much of Game Center, there seem to be design intentions belied, rather than explained, by the documentation.


To set up a match with the Local Player's friends, there's no need to use identifiers at all – I'd just missed the one method that still returns GKPlayers for friends: `loadRecentPlayers`. Its name doesn't mention friends, but there's an afterthought in the documentation which mentions it also returns players from the "legacy friends list." (I wonder how it's "legacy" – you can add people to it in iOS 13.)


gamePlayerID and teamPlayerID appear to work: you can access them and store them. But for players other than the Local Player, they seem, intentionally, not to persist between app launches or connections to Game Center. They change every time. Apparently they just can't be used for data persistence in the way playerIDs could be.

I started to play around with teamPlayerID value since Apple indicated in most cases we would be using the teamPlayerID value.


A) Once a match has been created, the teamPlayerID can be obtained for each player by looping through each player in the match (myMatch) data provided


for player in myMatch.players 
{ 
   print("teamPlayerID = \(player.teamPlayerID)") 
}


B) The teamPlayerID can also be obtained by calling the GKPlayer.loadPlayers(forIdentifiers:) function to obtain all player information. You can then loop through the provided GKPlayer "players" array to obtain the teamPlayerID for each player.


let playerIDs = myMatch!.players.map { $0.playerID } as [String] 
GKPlayer.loadPlayers(forIdentifiers: playerIDs) { (players, error) in ... 
for myGKPlayer in players 
{ 
   print("teamPlayerID = \(myGKPlayer.teamPlayerID)") 
}

(Note: Creating the player map array using $0.teamPlayerID does not result in any data being returned)



Issues Found:


1) If Player1 performs (A) and (B) then they will notice the teamPlayerID values for each player in the match from (A) are not the same values as the ones from (B)


2) If Player1 performs (A) and Player2 performs (A), then both players will have different teamPlayerID associated with them both? Meaning ...

  • Player1 sees a different teamPlayerID value for Player2 than Player2 sees for themselves
  • Player2 sees a different teamPlayerID value for Player1 than Player1 sees for themselves


3) Calling myGKPlayer.scopedIDsArePersistent( ) for each GKPlayer in the provided players array, in (B) above, always returns FALSE.


As a result of these issues, it does not seem the teamPlayerID value can be used to uniquely specify a particular "player" like everyone has mentioned.


I also confirmed one player cannot send data to another player (via GameKitHelper) since both players do not have the same teamPlayerID values that represent each player in the match.


The WWDC2019 video indicates the teamPlayerID values would remain consistent between all applications produced by my team, however, I clearly see the teamPlayerID value does not remain consistent within one single application only.


I will have to keep using playerID value until proper usage can be explained/fixed.