playgameservices / play-games-plugin-for-unity

Google Play Games plugin for Unity
Other
3.46k stars 965 forks source link

AndroidJavaException: java.lang.NoSuchMethodError #3002

Open sgeorge1970 opened 3 years ago

sgeorge1970 commented 3 years ago

When calling PlayGamesPlatform.Instance.LoadScores

I am getting this error: AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' signature='()I' in class Ljava.lang.Object;

I'm using 0.10.12 GPS unity package

this does not occur if I go to 0.9.64 GPS unity package

Any guidance would be great! Steve

ososmam commented 3 years ago

Same with PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution using 0.10.12

Quawetim commented 3 years ago

Same with PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution using 0.10.12

Same thing.

hbaInfinity commented 3 years ago

I can confirm the exact same message as the above people using 0.10.12. This was not happening in previous versions. This is also failing on the PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution call above.

The weird thing is that it is only happening on some devices. I am currently testing on a Samsung A30 on Android 10 (security patch 1st March 2021) where it all works perfectly, but another phone using the exact same Google Play log in, which is the Oppo AX5s on Android 8.1.0 (security patch 5th Feburary 2021) is failing with the issue above.

MoodyMuffin commented 3 years ago

When calling PlayGamesPlatform.Instance.LoadScores

I am getting this error: AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' signature='()I' in class Ljava.lang.Object;

I'm using 0.10.12 GPS unity package

this does not occur if I go to 0.9.64 GPS unity package

Any guidance would be great! Steve

Same problem!

mgrogin commented 3 years ago

same

hbaInfinity commented 3 years ago

Just as something else I have seen with this issue, it seems like it is affecting logging into the Google Play Games account on the device that it affects. Here is the current flow of what I am observing:

  1. Game Starts, The "Hi There, [ACCOUNT_NAME]" message shows up.
  2. Game attempts to download the Cloud Save for this user, but we get the error: AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' signature='()I' in class Ljava.lang.Object;
  3. When we enter into our Settings Menu, sometimes the game will detect that we have been logged in (using Social.localUser.authenticated), but occasionally we will be signed out again, so we have to manually sign back in.
  4. We have a button in game that attempts to save the data to the cloud, but when we call the ((PlayGamesPlatform)Social.Active).SavedGame.CommitUpdate, it returns back an error with AuthenticationError, which should only happen if the user isn't signed in.

This is happening on the Oppo AX5s on Google Play Services plugin 0.10.12, but everything works fine on a Samsung A30.

As a side note, these same devices work with this plugin on one of our other games, with the exact same code, but running on 0.10.04.

Any help on how to fix this is appreciated, as it is breaking almost all of our Google interactions on these devices.

MoodyMuffin commented 3 years ago

I made a quick temporary fix, not beautiful, but it worked for me. Here is the idea: In my case error happens inside AndroidSavedGameClient.cs in method 'AddOnFailureListenerWithSignOut' We add 'AddOnFailureListener' and try to call 'getStatusCode' from Exception object. But 'getStatusCode' is method for ApiException, which inherited from Exception. Exception doesn't have this method. I think this is the problem. So I cast Exception to ApiException if it possible, and after that trying to call getStatusCode. I do it in java class and call it from Unity.

Unity method which I'm calling instead of 'getStatusCode': public static int GetStatusCode(AndroidJavaObject exception) { using (var native = new AndroidJavaClass("com.<yourcompanyname>.ExceptionsUtils")) { return native.CallStatic<int>("GetStatusCode", exception); } } Code for native java class:

import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.CommonStatusCodes; @UnityCallable public class ExceptionsUtils { @UnityCallable public static int GetStatusCode(Exception ex) { if (ex instanceof ApiException) { return ((ApiException) ex).getStatusCode(); } return CommonStatusCodes.ERROR; } }

Also I replaced the same way other cases of using 'getStatusCode' for Exception object

hbaInfinity commented 3 years ago

Hey @MoodyMuffin ,

Thanks for the heads up on a way to fix this issue. I have used the code that you have provided, but I don't seem to be having much luck getting the c# code to nicely work with the native function. I've double checked on how to implement native .java classes (it seems like they made it much easier than it used to be before 2018.3), although I keep getting the NoSuchMethodError on the GetStatusCode call. Do you know if there is any specific location that the java file needs to exist (e.g. Plugins/Android), or defining the package of the java file (or does it only use the Package Name), or affected by Gradle build settings?

Any pointers on this would be appreciated!

MoodyMuffin commented 3 years ago

Hey @MoodyMuffin ,

Thanks for the heads up on a way to fix this issue. I have used the code that you have provided, but I don't seem to be having much luck getting the c# code to nicely work with the native function. I've double checked on how to implement native .java classes (it seems like they made it much easier than it used to be before 2018.3), although I keep getting the NoSuchMethodError on the GetStatusCode call. Do you know if there is any specific location that the java file needs to exist (e.g. Plugins/Android), or defining the package of the java file (or does it only use the Package Name), or affected by Gradle build settings?

Any pointers on this would be appreciated!

Hey In java file I define package name, like: 'package com.A.B.C.D;' java file is located inside app/src/main/java/com/A/B/C/D And in C# file I call new AndroidJavaClass("com.A.B.C.D.ExceptionsUtils")

Also, this package is added in proguard-unity.txt, maybe you should try it too

hbaInfinity commented 3 years ago

Thanks, After double checking, the java file does indeed get exported to the app/src/main/java/com/... directory when I build a gradle project, and I have defined the package name to be the same in the Java script and the C# script. The only main difference I have between the code is the that I let Unity generate the proguard-unity.txt, and that I am unable to get @UnityCallable compiling as it "Cannot Find Symbol". From what I have read up, it seems like just an interface in the Facebook plugin, but it doesn't seem like it does too much, and other examples I have seen do not require it.

I do hate Unity's lack of documentation on this stuff though, which would make things much easier than just a few dot points.

jonathanlindvall commented 3 years ago

We just ran into the exact same issue after adding a 2nd OAuth credential (to be able to test Games Services when building locally with the Debug certificate). In our case, it seems like the problem was related to Saved Games. Turns out we had a cloud save that had been uploaded from an Internal Test version of the app, signed with Play App Signing. The app signed with the Debug certificate was not able to download this cloud save and crashed with the NoSuchMethodError (getStatusCode).

We were able to solve it by deleting the Play Games data for the game through the Play Games app (Settings > Delete Play Games account & data). Not sure if this is the same issue that you guys are having, but it might be worth a try if you're using multiple OAuth credentials.

mgrogin commented 3 years ago

I'm still looking for a perfect solution but figure this will help the community find the actual problem. based on what @MoodyMuffin said I use this c# code that has an extension function that casts the AndroidJavaObject to com.google.android.gms.common.api.ApiException without having to use a java plugin.

So far I see that the object has been of 3 types: "com.google.android.gms.common.api.ApiException", "com.google.games.bridge.TokenResult", "java.lang.IllegalStateException" // doesnt have getStatusCode function

By doing this I was able to see this error: I/Unity: LoadScores failed: java.lang.IllegalStateException: Max results must be between 1 and 30 I think the bug might be related to this somehow...

Waiting to hear if anyone has any improvements or better solutions heres the code:

using System;
using System.Collections;
using System.Collections.Generic;
using GooglePlayGames.BasicApi;
using UnityEngine;

public static class AndroidJavaObjectUtilities
{
    public static AndroidJavaObject ClassForName(string className)
    {
        using (var clazz = new AndroidJavaClass("java.lang.Class"))
        {
            return clazz.CallStatic<AndroidJavaObject>("forName", className);
        }
    }

    // Cast extension method
    public static AndroidJavaObject Cast(this AndroidJavaObject source, string destClass)
    {
        using (var destClassAJC = ClassForName(destClass))
        {
            return destClassAJC.Call<AndroidJavaObject>("cast", source);
        }
    }

    public static int GetStatusCode(this AndroidJavaObject exception)
    {
        string[] casts = new string[]
        {
            "com.google.android.gms.common.api.ApiException",
            "com.google.games.bridge.TokenResult",
            "java.lang.IllegalStateException" // doesnt have getStatusCode function
        };
        int res;
        foreach (var cast in casts)
        {
            res = GetStatusCode(exception, cast);
            if (res !=  int.MinValue)
            {
                Debug.LogFormat("casted to {0} and returnes {1}", cast, res);
                return res;
            }
        }
        Debug.Log("failed to cast returning error code error");
        return (int)CommonStatusCodes.Error;
    }

    public static int GetStatusCode(this AndroidJavaObject exception, string castClass)
    {
        try
        {
            // com.google.games.bridge.TokenResult
            //using (var apiException = exception.Cast("com.google.android.gms.common.api.ApiException"))
            using (var apiException = exception.Cast(castClass))
            {
                return apiException.Call<int>("getStatusCode");
            }
        }
        catch (Exception e)
        {
            Debug.LogWarning("Failed to cast to ApiException. Error: " + e.Message);
            //return (int)CommonStatusCodes.Error;
            return int.MinValue;
        }
    }
}
mgrogin commented 3 years ago

There's still a bug with public void LoadScores(ILeaderboard board, Action callback) in PlayGamesPlatform.cs

https://github.com/playgameservices/play-games-plugin-for-unity/issues/2803

changed this:

mClient.LoadScores(
                        board.id,
                        LeaderboardStart.PlayerCentered,
                        board.range.count > 0 ? board.range.count : mClient.LeaderboardMaxResults(),
                        board.userScope == UserScope.FriendsOnly ? LeaderboardCollection.Social : LeaderboardCollection.Public,
                        timeSpan,
                        (scoreData) => HandleLoadingScores(
                            (PlayGamesLeaderboard)board, scoreData, callback));

to this:

 mClient.LoadScores(
                        board.id,
                        LeaderboardStart.PlayerCentered,
                        Math.Min(board.range.count, mClient.LeaderboardMaxResults()), //10,
                        board.userScope == UserScope.FriendsOnly ? LeaderboardCollection.Social : LeaderboardCollection.Public,
                        timeSpan,
                        (scoreData) => HandleLoadingScores(
                            (PlayGamesLeaderboard)board, scoreData, callback));

Still getting the error though..

leandersonralves commented 3 years ago

Hi folks, until some seconds ago, I was fighting against this issue. But, I found a problem in my code. I was building a Metadata with a PNG cover data with a Array Lenght equals zero.

SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder();
        builder = builder
            .WithUpdatedPlayedTime(TimeSpan.FromSeconds(Time.unscaledTime))
            .WithUpdatedDescription("Saved game at " + DateTime.Now);
        builder = builder.WithUpdatedPngCoverImage(new byte[0]); //WRONG LINE

I just remove this wrong line and solved. tadãh!

I suposse that I must pass a array with length zero in case without a png cover.

mgrogin commented 3 years ago

Im still getting this message "Max results must be between 1 and 30" from the HandleLoadingScores function sending rowcount=75 . I tried maxing it to 25, that get rid of the message but I'm not getting the leaderboard results. any ideas?

internal void HandleLoadingScores(
            PlayGamesLeaderboard board,
            LeaderboardScoreData scoreData,
            Action<bool> callback)
        {
            bool ok = board.SetFromData(scoreData);
            if (ok && !board.HasAllScores() && scoreData.NextPageToken != null)
            {
                int rowCount = board.range.count - board.ScoreCount;          
 //              rowCount = Math.Min(rowCount, mClient.LeaderboardMaxResults());

                // need to load more scores
                mClient.LoadMoreScores(
                    scoreData.NextPageToken,
                    rowCount,
                    (nextScoreData) =>
                        HandleLoadingScores(board, nextScoreData, callback));
            }
            else
            {
                callback(ok);
            }
        }
mgrogin commented 3 years ago

@aerialninja I see you made some changes to the github What do you think about this change? https://github.com/playgameservices/play-games-plugin-for-unity/issues/3002#issuecomment-825010982

What do we need to do to get it in the next build and to make sure it's correct? what's the procces? thanks in advance!

RPGameStudio commented 3 years ago

Had same issue. Problem was in play services initialization: I forgot to add .EnableSavedGames() while setup confuguration.

image
MarkGree commented 3 years ago

Same issue. I don't know why it appears. Sometimes I sign in successfully but sometimes this error occures and I can't load my saved game. Logs: https://justpaste.it/98hbi Code PlayGames.cs: https://paste.ofcode.org/YjuUgCjp75ndzJ9PZg9iJt SaveManager.cs: https://paste.ofcode.org/7ts3dtEjHqPrxmH5hCHysA CloudSaveController.cs: https://paste.ofcode.org/34LujFi7MqjcvK7PkL2dfR2

GooglePlayGames Plugin Version is 0.10.12

ilkancelikMA commented 3 years ago

We also started having the same error @MarkMa-LS mentioned above started yesterday. We saw some errors related to SaveGames API but we fixed those by updating the SHA-1. It did decrease the amount but we still have a lot of AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' signature='()I' in class Ljava.lang.Object; coming from players. We also have 2 devices within the team having the same issue. GCP window pops up but then throws this error.

MarkGree commented 3 years ago

We also started having the same error @MarkMa-LS mentioned above started yesterday. We saw some errors related to SaveGames API but we fixed those by updating the SHA-1. It did decrease the amount but we still have a lot of AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='getStatusCode' signature='()I' in class Ljava.lang.Object; coming from players. We also have 2 devices within the team having the same issue. GCP window pops up but then throws this error.

While developing the game further, I haven't seen this problem for the last two days, but is there a 100% fix for it?

bakicaglar commented 3 years ago

I was getting this error while trying to get all time high score of the current user. I changed my code from this:

PlayGamesPlatform.Instance.LoadScores(
            GPGSIds.leaderboard_test,
            LeaderboardStart.PlayerCentered,
            100,
            LeaderboardCollection.Public,
            LeaderboardTimeSpan.AllTime,
            data => {
                if (data.PlayerScore == null) {
                    Debug.Log("User has no Score on leaderboard");
                } else {
                    Debug.Log(data.Valid);
                    Debug.Log(data.Id);
                    Debug.Log(data.PlayerScore);
                    Debug.Log(data.PlayerScore.userID);
                    Debug.Log(data.PlayerScore.formattedValue);
                }
            });

to this:

PlayGamesPlatform.Instance.LoadScores(
            GPGSIds.leaderboard_test,
            LeaderboardStart.PlayerCentered,
            1,
            LeaderboardCollection.Public,
            LeaderboardTimeSpan.AllTime,
            data => {
                if (data.PlayerScore == null) {
                    Debug.Log("User has no Score on leaderboard");
                } else {
                    Debug.Log(data.Valid);
                    Debug.Log(data.Id);
                    Debug.Log(data.PlayerScore);
                    Debug.Log(data.PlayerScore.userID);
                    Debug.Log(data.PlayerScore.formattedValue);
                }
            });

and the error dissapeared.

SanyaIV commented 3 years ago

We've been seeing this exception as well when trying to load saved games resulting in the callback never being called and players being stuck on loading screens. Is there any workaround for this?

frostscene commented 3 years ago

We've been seeing this exception as well when trying to load saved games resulting in the callback never being called and players being stuck on loading screens. Is there any workaround for this?

Same here !!!!

YounusShalaby commented 3 years ago

Guys, Are you sure you have enabled Saved Games on Developer Console?

pierreserin commented 2 years ago

Same here, this error pops up on some (not all) devices when trying to load a cloud save with version 10.12. Need a fix ASAP

YounusShalaby commented 2 years ago

1- Try Using the Plugin Without Overriding the Default Social Platform ( https://github.com/playgameservices/play-games-plugin-for-unity#advanced-using-the-plugin-without-overriding-the-default-social-platform )

2- make sure you have enabled "saved game" on google play developer console

3- if you are using proguard check this ( https://github.com/playgameservices/play-games-plugin-for-unity#decreasing-apk-size )

number (1) resolved my problem, (2) and (3) were also problems with my project

schouffy commented 2 years ago

I had the same issue, and wasted a couple hours to try and solve it because of poor error handling from the plugin. I was just trying to get the player high score, so called PlayGamesPlatform.Instance.LoadScores with a rowCount of 0 (because I have no interest in other players scores..) When I changed it to 1, it started working. If I had an explicit error message, it'd had been just a matter of seconds, but poor error handling + large iteration time (because everything only works on device) is a bad combination.

To be able to read a proper error message, I modified AndroidClient.AddOnFailureListenerWithSignOut to just silent the exception. It's bad but for development time it helps a lot.

private void AddOnFailureListenerWithSignOut(AndroidJavaObject task, Action<AndroidJavaObject> callback)
        {
            AndroidTaskUtils.AddOnFailureListener(
                task,
                exception =>
                {
                    try
                    {
                        var statusCode = exception.Call<int>("getStatusCode");
                        if (statusCode == /* CommonStatusCodes.SignInRequired */ 4 ||
                            statusCode == /* GamesClientStatusCodes.CLIENT_RECONNECT_REQUIRED */ 26502)
                        {
                            SignOut();
                        }
                    }
                    catch (Exception)
                    {
                    }

                    callback(exception);
                });
        }
LiveWithoutFear commented 2 years ago

Guys, Are you sure you have enabled Saved Games on Developer Console?

I didn't bother checking this because I KNEW I had this enabled! But after reading I thought "Ah you know what I'll double check it" Lesson being, always double check! F#cker was NOT enabled!

LiveWithoutFear commented 2 years ago

We just ran into the exact same issue after adding a 2nd OAuth credential (to be able to test Games Services when building locally with the Debug certificate). In our case, it seems like the problem was related to Saved Games. Turns out we had a cloud save that had been uploaded from an Internal Test version of the app, signed with Play App Signing. The app signed with the Debug certificate was not able to download this cloud save and crashed with the NoSuchMethodError (getStatusCode).

We were able to solve it by deleting the Play Games data for the game through the Play Games app (Settings > Delete Play Games account & data). Not sure if this is the same issue that you guys are having, but it might be worth a try if you're using multiple OAuth credentials.

Well even after my previous post and enabling Saved Games in the console I still received an error. But it turns out that removing my games data from the Google Play Games app within its settings did the trick! I was able to successfully save my game data to Google Cloud after I did this. Hoo-rah...

adbourdages commented 2 years ago

About the noSuchMethod error. getStatusCode is called via JNI in two locations: AndroidClient and AndroidSavedGameClients. The methods are similar but with a crucial difference: a check for `Misc.IsApiException' is missing in AndroidClient.

Adding it should fix the problem. This is valid for 0.10.14

private void AddOnFailureListenerWithSignOut(AndroidJavaObject task, Action<AndroidJavaObject> callback)
        {
            AndroidTaskUtils.AddOnFailureListener(
                task,
                exception =>
                {
                    if( Misc.IsApiException(exception) )
                    {
                        var statusCode = exception.Call<int>("getStatusCode");
                        if( statusCode == /* CommonStatusCodes.SignInRequired */ 4 ||
                            statusCode == /* GamesClientStatusCodes.CLIENT_RECONNECT_REQUIRED */ 26502 )
                        {
                            SignOut();
                        }
                    }
                    callback(exception);
                });
        }
sdma241 commented 3 months ago

I solved my problem When I changed rowCount from 100 to 25 on PlayGamesPlatform.Instance.LoadScores , then it started working.