playgameservices / play-games-plugin-for-unity

Google Play Games plugin for Unity
Other
3.43k stars 954 forks source link

Save games started recently failing due to `java.lang.IllegalStateException: Must include Drive.SCOPE_APPFOLDER to use snapshots!` #3076

Closed karliss closed 2 years ago

karliss commented 2 years ago

Last week I was testing my game and the saves were working correctly, but this week it started failing.

Initially the error was masked due to poor error handling in play games plugin for unity #3002 . After I added a bunch of debug logging inside play games plugin I found that in my case the cause was:

java.lang.IllegalStateException: Must include Drive.SCOPE_APPFOLDER to use snapshots!

As far as I can tell I should already have SCOPE_APPFOLDER. In Google Cloud Platform console/OAuth consent screen I have .../auth/drive.appdata scope and in the initialization code I have

PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
               .EnableSavedGames()
               .Build();

From what I understand EnableSavedGames() was supposed to request the SCOPE_APPFOLDER.

SanyaIV commented 2 years ago

We've been getting the exception you reference as masking the error. Not sure if the root cause is the same but have you found any workarounds for the issue?

karliss commented 2 years ago

No workarounds. I really don't want having to do timeouts for calls to play games plugin library.

I added

Debug.LogError($"Play services exception {exception.Call<string>("toString")}");

before all lines in in play games-plugin that call foo.Call<int>("getStatusCode"); . That might give you more meaningfull error message since java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' only tells that the play games plugin received an exception with different type than it expected thus no getStatusCode method. 3002 has been opened for a while and people mention various things helping them, seeing the full error message might give you some clues if your case is caused by something you can fix yourself like misconfiguration. Google should still fix the fact that for some errors the callback isn't being called as that makes the whole thing unusable.

One more not exactly workaround is that you can prevent the automatic sign in by opening "Settings/change account for games" in the play games app and choosing "change/sign out" either from specific game or all. That way you can at least temporary test rest of the game without having to change the code and remove the play games specific parts.

Another observation is that some of my colleges said that on their phones everything works. Trying to update and clearing cache for Google Play Games and Google Play Services didn't help.

frostscene commented 2 years ago

We are getting same exception "Save games started recently failing due to java.lang.IllegalStateException: Must include Drive.SCOPE_APPFOLDER to use snapshots!" need to be fixed asap.!!!!

SanyaIV commented 2 years ago

No workarounds. I really don't want having to do timeouts for calls to play games plugin library.

I added

Debug.LogError($"Play services exception {exception.Call<string>("toString")}");

before all lines in in play games-plugin that call foo.Call<int>("getStatusCode"); . That might give you more meaningfull error message since java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' only tells that the play games plugin received an exception with different type than it expected thus no getStatusCode method. 3002 has been opened for a while and people mention various things helping them, seeing the full error message might give you some clues if your case is caused by something you can fix yourself like misconfiguration. Google should still fix the fact that for some errors the callback isn't being called as that makes the whole thing unusable.

One more not exactly workaround is that you can prevent the automatic sign in by opening "Settings/change account for games" in the play games app and choosing "change/sign out" either from specific game or all. That way you can at least temporary test rest of the game without having to change the code and remove the play games specific parts.

Another observation is that some of my colleges said that on their phones everything works. Trying to update and clearing cache for Google Play Games and Google Play Services didn't help.

Thanks. From the actual error we get we seem to be getting the same error as you, Drive.SCOPE_APPFOLDER, our workaround for now is to use the error handling code from the other thread but that doesn't solve the underlying issue. Have you looked into manually requesting the scope? Haven't had time to today but that might be the next thing we try.

karliss commented 2 years ago

Have you looked into manually requesting the scope? Haven't had time to today but that might be the next thing we try.

If by manually requesting scope you meant Builder().AddOauthScope(scope) I considered it but didn't try since EnableSavedGames() was supposed to do exactly that https://github.com/playgameservices/play-games-plugin-for-unity/blob/2e1d95d45ce05230e2da4e7a8c9f2cde664e69c6/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs#L272-L275

Logcat also contained some lines that seemed to indicate that login process requested drive.appdata scope. Didn't want to share those since it was unclear if any of request fields contains a session token or some similar private data.

HasPermissions and RequestPermission on the other hand looks like something worth trying, in case the scope somehow gets dropped not granted or to give extra confirmation that indeed has been granted but still cause the error mentioned above. Only problem is I am not sure exact format for scope/permission name since the example uses just "email" which is not the full scope URL or the identifiers used in Cloud console.

tech4happie commented 2 years ago

Same issue. My app has been in production for 10 months. It is used to save and retrieve snapshots with the drive.appdata sign-in scope as below:

GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
                .requestScopes(Scope(DriveScopes.DRIVE_APPDATA)).build()

Yesterday I found save/retrieve no longer work (same error: "java.lang.IllegalStateException: Must include Drive.SCOPE_APPFOLDER to use snapshots!"). I'd like to report to follow the issue.

akorolczuk commented 2 years ago

We are experiencing the same issue for last couple of days. Seems that Drive.SCOPE_APPFOLDER is requested as it should yet some saves (not all) fail.. Has anyone reached to Google about this?

SanyaIV commented 2 years ago

HasPermissions returns true for drive.appdata even when the issue is happening, but requesting it again with RequestPermission actually fixes our issue.

To check for permission (always returns true for us) PlayGamesPlatform.Instance.HasPermission("https://www.googleapis.com/auth/drive.appdata")

To request permission PlayGamesPlatform.Instance.RequestPermission("https://www.googleapis.com/auth/drive.appdata", status => Debug.Log(status));

The above gave us exceptions however citing "getEmail" so I commented out lines 154 through 156 in AndroidTokenClient.cs (we don't request these things so don't matter for us but might for you)

Edit: Actually I think I was wrong, it wasn't requesting drive.appdata that fixed it, it was requesting drive.appfolder... I think.

string[] scopes = { "https://www.googleapis.com/auth/drive.appdata", "https://www.googleapis.com/auth/drive.appfolder" };
PlayGamesPlatform.Instance.RequestPermissions(scopes, status => Debug.Log(status));

But HasPermission for drive.appfolder is false before and after requesting it so I'm not really sure if HasPermission is working as intended.

karliss commented 2 years ago

According to https://developers.google.com/identity/protocols/oauth2/scopes#drive there is no such thing as drive.appfolder so maybe passing invalid scope somehow reset broken state. But it doesn't list games_lite either so who now if that documentation is up to date.

SanyaIV commented 2 years ago

I have no idea, can just verify that it works for us. Our solution right now is try operation, if not successful request permissions again and when that's done retry operation.

karliss commented 2 years ago

@SanyaIV How do you know if operation is not successful if it throws a java exception and doesn't invoke the callback. Did you also modified the exception handler so that it checks the exception type and calls callback in case it has unexpected type instead of trying to call getStatusCode unconditionally?

SanyaIV commented 2 years ago

@SanyaIV How do you know if operation is not successful if it throws a java exception and doesn't invoke the callback. Did you also modified the exception handler so that it checks the exception type and calls callback in case it has unexpected type instead of trying to call getStatusCode unconditionally?

Using this and replaced all calls in plugin to use that instead https://github.com/playgameservices/play-games-plugin-for-unity/issues/3002#issuecomment-824931310

karliss commented 2 years ago

This is pure speculation from me. I am slightly worried that it was matter of retrying and it might be the same issue as https://github.com/playgameservices/android-basic-samples/issues/335 and https://github.com/playgameservices/android-basic-samples/issues/338 .Retrying may increase chance of success but if the error rate is sufficiently high it may also result in hitting the rate limits. Which I assume is what happens in the second case 338 except due to using java version of library where it's easier to catch errors they might have had a retry code already so instead of weird scope error it was noticed as rate limit error. First one mentions We expect that the error rate will reduce to 0 organically by mid September. it is middle of September but maybe their changes instead of reducing errors to 0, turned them into different error.

karliss commented 2 years ago

There is also https://stackoverflow.com/questions/69243404/caused-by-must-include-drive-scope-appfolder-to-use-snapshots which suggests that recent change in default behavior is at fault. I remember seeing that popup once when i was reinstalling stuff trying to fix this issue, it still failed even though I checked "See create and delete it's own configuration in your Google Drive". Also in case user denies the permission I would expect HasPermission to return false or login to fail.

rlzicar commented 2 years ago

As a workaround, I tried changing InitializeTokenClient() in AndroidClient.cs like so:

if (mConfiguration.EnableSavedGames) {
            mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/drive.appdata");  
            mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/drive.appfolder");  // added this line  
}

And it seems to be working fine.

frostscene commented 2 years ago

As a workaround, I tried changing InitializeTokenClient() in AndroidClient.cs like so:

if (mConfiguration.EnableSavedGames) {
            mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/drive.appdata");  
            mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/drive.appfolder");  // added this line  
}

And it seems to be working fine.

it didn't work for us

karliss commented 2 years ago

"drive.appfolder" Initially it didn't work for me, and even started things to act more buggy than before by printing new kinds of errors to logcat. But after one more round of manually clearing data an cache for everything and forcing logout, it started working. I was able to repeatedly sign in, do save synchronization, sign out. To confirm that this indeed related to "drive.appfolder" scope and not just Google engineers flipping switches while everyone here are going crazy, I tried removing "drive.appfolder" and it started failing again. Added it back + manual cleanup and it started working again.

The scope itself is a bit weird. Mismatch between "Drive.SCOPE_APPFOLDER" and "https://www.googleapis.com/auth/drive.appdata" indicate that maybe at some point something got renamed. Some parts of documentation say that it is supposed to be "https://www.googleapis.com/auth/drive.appfolder" others ".../drive.appdata". https://developers.google.com/identity/protocols/oauth2/scopes and only mentions "drive.appdata". This suggest that they are aliases which got renamed to "appDataFolder" in v3. I also tried adding "https://www.googleapis.com/auth/drive.appdataFolder" as scope but that didn't work at all.

rlzicar commented 2 years ago

So I tested it on several devices and unfortunately, the "drive.appfolder" workaround doesn't always work. On some devices, even after clearing the cache and signing out and back in, it still sometimes (although not very often) throws the same exception as before.

akorolczuk commented 2 years ago

We managed to get Google to look into this and this is what they just sent to us

“The issue was on our end and has been fixed (might take few days till it is 100% rolled to all end users). Please continue monitoring.”

Hopefully we should see this declining over next hours/days