GooglePlayServices / Leaderboard (anhand Beispiel)

numanoid

numanoid

Dauergast
460
Hallo Leute,

hab zwar nicht so viel Hoffnung, aber wer nicht probiert ..

Ich habe u.a. ein Spiel im Google PlayStore und das schon seit 2011. Das Spiel war bis vor kurzem noch mit Eclipse entwickelt. Vor einigen Jahren 6-7 Jahren hab ich das Spiel auch um die Nutzung der GooglePlayService erweitert, so dass die User ihren HighScore und ihre Meilensteine (Achievements) mit anderen Usern vergleichen können.

Leider war ich von Seite Google gezwungen, das Spiel auf eine neuere API umzustellen. Mittlerweile arbeite ich mit anderen meiner Apps auch schon mit Android Studio, also hab ich die Weihnachtstage genutzt, und das Spiel auf Android Studio und die neue TargetApi 31 portiert. Aber nicht ohne Verluste!

Eigentlich dachte ich, dass das Umstellung bezüglich der GooglePlayServices ein Klacks sein sollte, da es früher alles eher Workarounds von Google gab. Z.B. musste man seine Activity von BaseGameActivity ableiten, und dazu spezielle Libraries extern einbinden usw.
Aber Pustekuchen, ich bekomme es mit den neuen Methode nicht hin. Da gibt es zwei APIs, v1 und v2, und was man im Internet findet, klappt alles aus irgendwelchen Gründen nicht.

Deshalb frag ich hier mal nach, ob jemand GooglePlayServices in seinen(m) Spiel(en) verwendet. Das Leaderboard/Highscore-Feature würde mir schon reichen, wenn ich es wieder zur Verfügung stellen könnte. Aktuell ist mein Spiel wieder im PlayStore, aber eben mit deaktivierten GooglePlayServices.

Ich bräuchte einen abgespeckten Bespiel-Code, wo man das
- komplette SignIn (in die GooglePlay-Services) sieht, und
- das Synchronisieren des Highscores des User

Es soll sich aber hier für mich niemand extra schlau machen. Das Thema ist komplex und man verliert Stunden. Ich suche hier nur jemanden, der das funktionsfähig nutzt, und den entsprechenden Code teilen möchte/würde.

LG
 
Zuletzt bearbeitet:
Bin leider immer noch nicht weiter gekommen. Ich versuche mal die relevanten Code-Stellen der Activity hier reinzugeben. Vielleicht hat doch jemand ja eine Idee, oder sieht den Unterschied zu seinem funktionierenden Code.

Code:
public GoogleSignInClient mGoogleSignInClient = null;
public GoogleSignInAccount mGoogleSignedInAccount = null;

public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  . . .

  googleSignInGetClient();
}

private void googleSignInGetClient () {

  mGoogleSignInClient = GoogleSignIn.getClient(this,
       new GoogleSignInOptions.Builder(
         GoogleSignInOptions.DEFAULT_SIGN_IN)
       .build());

  Intent signInIntent = mGoogleSignInClient.getSignInIntent();
  startActivityForResult(signInIntent, RC_SIGN_IN);
}

public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  super.onActivityResult(requestCode, resultCode, data);

  Log.w(TAG, "onActivityResult(): requestcode: "+requestCode+", resultCode: "+resultCode);

  switch (requestCode) {
    case RC_SIGN_IN: {

      GoogleSignIn.getSignedInAccountFromIntent(data)
      .addOnSuccessListener(this, new OnSuccessListener<GoogleSignInAccount>() {
       @Override
       public void onSuccess(GoogleSignInAccount account) {
        Log.d(TAG, "Sign in success");
    
       }
      })
      .addOnFailureListener(this, new OnFailureListener() {
       @Override
       public void onFailure(@NonNull Exception e) {
        Log.e(TAG, "Sign in failed", e);
       }
      });

   break;
  }
}
}

Wenn die App started, kommt auch der Dialog hoch, wo der User seinen Account auswählen bzw. damit das Login bestätigt. Wählt man dann dort den Account aus, kommt es zum Fehler.

Ich hab auch schon andere Code-Varianten aus dem Internet probiert. Aber der Fehler ist letztlich der Gleiche, also dass der Sign-Prozess nicht klappt mit der Exception:
com.google.android.gms.common.api.ApiException: 10 (=DEVELOPER)

Ich hab das ganze sowohl mit Release- oder Debug-Signierung der APP getestet, aber kein Unterschied.

Stacktrace:

Code:
2023-01-29 14:55:23.865 11457-11457/? D/de.mdliquid.maze3d.Maze3D_Activity: onCreate() ...
2023-01-29 14:55:23.875 11457-11457/? D/de.mdliquid.maze3d.Maze3D_MainView: onInit() ...
2023-01-29 14:55:24.105 11457-11457/? D/de.mdliquid.maze3d.Maze3D_MainView: onDraw() ...
2023-01-29 14:55:26.635 897-3139/? E/ActivityTrigger: activityResumeTrigger: not whiteListedde.mdliquid.maze3d/de.mdliquid.maze3d.Maze3D_Activity/23
2023-01-29 14:55:26.636 897-3139/? E/ActivityTrigger: activityResumeTrigger: not whiteListedde.mdliquid.maze3d/de.mdliquid.maze3d.Maze3D_Activity/23
2023-01-29 14:55:26.639 11457-11503/? D/DecorView: onWindowFocusChangedFromViewRoot hasFocus: true, DecorView@1b16f83[Maze3D_Activity]
2023-01-29 14:55:26.655 11457-11457/? W/de.mdliquid.maze3d.Maze3D_Activity: onActivityResult(): requestcode: 1, resultCode: 0
2023-01-29 14:55:26.665 11457-11457/? E/de.mdliquid.maze3d.Maze3D_Activity: Sign in failed
    com.google.android.gms.common.api.ApiException: 10:
        at com.google.android.gms.common.internal.ApiExceptionUtil.fromStatus(com.google.android.gms:play-services-base@@18.1.0:3)
        at com.google.android.gms.auth.api.signin.GoogleSignIn.getSignedInAccountFromIntent(com.google.android.gms:play-services-auth@@20.4.1:3)
        at de.mdliquid.maze3d.Maze3D_Activity.onActivityResult(Maze3D_Activity.java:254)
        at android.app.Activity.dispatchActivityResult(Activity.java:7476)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4499)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4548)
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1916)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Ich hab auch schon statt DEFAULT_SIGN_IN, DEFAULT_GAMES_SIGN_IN probiert. Da kommt kein Account-Auswahl Dialog, sondern gleich der Fehler.
 
Zuletzt bearbeitet:
Was ich mich auch immer Frage ist, ob ich denn die GooglePlayServices aus AndroidStudio heraus testen kann. Zum einen, mit debug-Keys, oder release-Keys. Oder schlimmer, dass es tatsächlich nur geht, wenn man Tester einrichtet. Irgendwo steht, dass man als Entwickler nicht automatisch Tester ist. Aber dazu muss ich wieder ein APK erstmal releasen laut Doku, was Schwachsinn ist. Ich will doch nicht jeden keinen Schritt oder Debugging durch ein Erzeugen eines Releases machen müssen.
 
Bin mittlerweile etwas weitergekommen ..

Ich hab noch weitere Kombinationen (verschiedener Code jeweils mit Debug- oder Release-Build) und es gab dann doch eine Variante (man braucht Release) wo es ging. D.h. ich kann jetzt bei App Start triggern, dass der User seinen Account wählen/bestätigen kann, mit der dann die App gespielt wird:

Code:
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {

        Log.e(TAG, "handleSignInResult ..");
        try {
            Log.e(TAG, "handleSignInResult " + completedTask.isSuccessful());
            currentAccount = completedTask.getResult(ApiException.class);
            Log.e(TAG, "account: " + currentAccount.getDisplayName());
            mLeaderboardsClient = Games.getLeaderboardsClient(this, currentAccount);
            .

Im logcat sehe ich dann auch den Account-Namen, und mittels diesem, kann man sich dann z.B. einen sogn. LeaderboardsClient besorgen. Es kommt zu keinem Fehler und etwas das nicht NULL ist zurück, so dass ich mir sicher bin, das es eigentlich funktioniert haben sollte.

Mit diesem LeaderboardsClient kann ich dann auch gleich am Anfang mal den Spielstand (ich hab 2 Verschiedene) hochladen, den ich auch lokal in einem File speichere, falls z.B. beim letzten Spielen gar kein Internet vorhanden war, um den Spielstand hochzuladen:
Code:
mLeaderboardsClient.submitScore(getResources().getString(R.string.leaderboard_highscore), GamePlay.getInstance().getTotalScore());
mLeaderboardsClient.submitScore(getResources().getString(R.string.leaderboard_highscore_rand), GamePlay.getInstance().getTotalRandScore());

Auch dabei kommt kein Fehler.

Ein Problem besteht aber jetzt noch darin, dass ich das Leaderboard zum Spiel nicht öffnet. Über einen Intent wird normalerweise eine solche Übersicht standardisiiert von Google präsentiert, wo der User seinen eigenen Score, und die Einreihung unter allen Users, die das Spiel gespielt haben, sehen kann.

Wenn ich das versuche via diesem Code:
Code:
((Maze3D_Activity)ApplSettings.getInstance()._mainActivity).mLeaderboardsClient.getAllLeaderboardsIntent()
                                                .addOnSuccessListener(new OnSuccessListener<Intent>() {
                                                    @Override
                                                    public void onSuccess(Intent intent) {
                                                        Log.d(TAG,"viewLeaderBoards; starting activity for result");
                                                        //((Activity)(v.getContext())).startActivityForResult(intent, 1000);
                                                        ((Activity)(v.getContext())).startActivity(intent);
                                                    }
                                                })
                                                .addOnFailureListener(new OnFailureListener() {
                                                    @Override
                                                    public void onFailure(Exception e) {
                                                        Log.d(TAG, "leaderboard problem: \n"+e.toString());
                                                    }
                                                });


Dann kommt eine sehr seltsame Fehlermeldung im logcat:
Code:
leaderboard problem:
com.google.android.gms.common.api.ApiException: 17: API: Games.API is not available on this device. Connection failed with: ConnectionResult{statusCode=INTERNAL_ERROR, resolution=null, message=null}

Seltsam, weil es sich so anhört, als ob auf meinem Phone (OnePlus 6T) mit dem ich teste, etwas essentielles fehlen würde. Aber auf dem Phone gehen die Game-Services ohne Problem, sogar noch mit meinem älteren Spiel. Ich hab jetzt sogar ein Galaxy S10, welches den gleichen Fehler liefert.
Der Fehler scheint zu bedeuten, dass in der App etwas (Library, ...) nicht eingebunden wird, was notwendig ist.

Bisher nicht herausgefunden, was das sein soll, den ich binde im build.gradle ja alles ein was ich sonst so vergleichbar gelesen habe:
Code:
dependencies {
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'com.google.android.gms:play-services-location:21.0.1'
    implementation 'com.google.android.gms:play-services-games:23.1.0'
    implementation 'com.google.android.gms:play-services-auth:20.4.1'
}

Ich reporte dies auch hier an Euch, in der Hoffnung, dass Ihr vielleicht nicht genau mein Problem mal hattet, aber dass Ihr vielleicht mal etwas anderes (als die Games.API) genutzt habt, und einen Fehler ....API is not available hattet, und noch wisst, woran es da genau gelegen hat und wie Ihr es beheben konntet.
 
Zuletzt bearbeitet:
Update mit Neuigkeiten:

Ich war in Kontakt mit dem Developer Support. Anfangs kam nur so allgemeine Infos zurück, nach dem Motto "ist der Computer auch eingeschaltet". Ich übertreibe natürlich. Aber ich bin hartnäckig geblieben, und darauf kam den wirklich was Hilfreiches:

Man sagte mir, dass in der Release-APK die APP_ID den Wert 12345678.0 (Beispiel) hat. Eigentlich ist aber 12345678 richtig.

Im Android Manifest hatte ich diese ID bisher immer direkt stehen, also
Code:
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="12345678" />

Das hat scheinbar früher funktioniert (als es noch in Eclipse war), aber das Android Studio mag das nicht, bzw. mach daraus einen Float-Wert, der aber bei der Authentisierung nicht matched.

Ich hab jetzt einfach den Wert in einer String-Resource abgelegt, und im Manifest referenziert:
Code:
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id"/>

Siehe da, die ID wird korrekt in die Release-APK geschrieben, wie man mit dem Tool 'apktool' dann auch nachschauen kann.
Noch besser, auf meinem Smartphone geht jetzt auch das Leaderboard auf, und wie ich testen konnte, wird der Spielstand auch an den Server übertragen und aktualisiert sich somit im Leaderboard.

Wie gesagt, es funktioniert jetzt mit meinem Phone (OnePlus 6T, Android 9.0). Aber auf einem Samsung S9 und Android 8.0 geht es nicht.

Die aktuelle Version ist im Google-PlayStore verfügbar. Wenn mir jemand einen Gefallen tun will, kann er meine App auf sein Phone installieren (ist ja kostenlos)
Labyrinth 3D
mal das erst Labyrinth spielen und mal berichten, was passiert, wenn man auf der ersten Seite der App oben auf den Pokal tippt. Eigentlich soll das Leaderboard sich öffnen und man soll seinen eigenen Score, und das Ranking zwischen den anderen Spieler sehen.

Die Info für mich wäre, Leaderboard öffnet sich ja/nein, der eigene Score wird angezeigt ja/nein und welches Smartpone mit welcher Android-Version wurde verwendet. Z.B. per PM (privater Message) hier im Forum.
Dies würde mir einen Überblick geben, ob es in den meisten Konstellationen geht, oder ehr nicht. Vielen Dank.
 
Zuletzt bearbeitet:

Ähnliche Themen

E
  • erli2909
Antworten
14
Aufrufe
2.130
numanoid
numanoid
Zurück
Oben Unten