Google Play Services in App implementieren

  • Antworten:12
Heretsu
  • Forum-Beiträge: 37

03.12.2014, 16:44:33 via Website

Guten Abend, ich würde gerne die Google Play Services in meiner App benutzen, genauer genommen die Leaderboards und danach Achievements. Einen hierfür benötigten Account habe ich bereits.
Ich habe folgendes Tutorial von Google gelesen: https://developers.google.com/games/services/android/leaderboards
Und mir bereits die Tabelle in der Developer Console erstellt.
Nun muss ich an Eclipse und eine Verbindung zwischen der App und den Google Play Services erstellen.
Hier scheitert es bereits. Im Tutorial von Google wird gesagt, dass man sich die Samples runter laden sollte und dass "BaseGameUtils" als library in Eclipse angegeben werden soll. Wie macht man dies richtig? Ich habs jetzt einige male versucht aber Ich gehe stark davon aus, dass es jedes mal falsch war da z.B "extend BaseGameUtils" von Eclipse als Fehler gesehen wurde und ich stattdessen "BaseGameActivity" importieren solle. Ich habe beim Googlen gelesen, dass eine Datei namens "make_eclipse_compat" mit den Samples gedownloadet wird und man diese Datei über cmd öffnen soll, so wird "BaseGameUtils" Eclipse kompatibel. Dies geht aber auch nicht. Wenn ich diese Datei öffne, erscheint für einen bruchteil einer Sekunde das typische cmd Fenster wo ein Fehler beschrieben wird, ob dies nun relevant ist, weiß ich leider nicht. Aber jemand, der die Google Play Services schon einmal benutzt hat, könnte mir wahrscheinlich helfen ;)
Dies wäre der erste Schritt und mein erstes Problem dabei. Es würde mich sehr freuen, wenn sich einer meinem Problem zuwenden kann und mir bei der Implementierung helfen könnte.

MfG

Antworten
pepperonas
  • Forum-Beiträge: 434

04.12.2014, 20:32:18 via Website

Jo, habe schon mal einen kleinen Multiplayer mit den GPS gemacht.. Leider bin ich zeichnerisch alles andere als begabt, weshalb das Projekt auf Eis liegt :-/ vielleicht will sich ja jemand dem Projekt (mit)annehmen?
Meines Wissens sind die BaseGameUtils nicht mehr State of the Art. Aber dennoch sollten sie implementierbar sein...

Meine Main sieht zu Beginn so aus...

public class Main extends BaseGameActivity implements View.OnClickListener, RealTimeMessageReceivedListener,
        RoomStatusUpdateListener, RoomUpdateListener, OnInvitationReceivedListener, SensorEventListener {

Glaube das wird dir noch nicht groß helfen, oder?

Vielleicht vorweg... das Google-Tutorial funktioniert ungefähr so:
Such dir ein Beispiel-Spiel raus und nimm das als "Quelle" (darüber bekommst du dann auch den GameHelper und den ganzen anderen Funktionalitäten, so auch die Leaderboards etc - im Prinzip könntest du so auch gleich die Cloud einbinden um zB Spielstände zu sichern...)
mein Tipp: ButtonClicker 2000 ist recht anschaulich erklärt.
Das hattest du aber, so wie ich deinen Beitrag verstehe, auch schon auf dem Radar. :)

Und nun zu dem eigentlichen Problem... (jedenfalls vermute ich dass es das ist^^)
Du musst die GooglePlayServices für die Google-Beispiele selbst hinzufügen, sonst werden sie nicht von der IDE erkannt und das wiederum macht ein Programm was sich an den Beispielen bedient gleichzeitig mit "unbrauchbar"...
Habs leider auch nicht mehr 100%tig im Kopf wie es funktioniert. Aber wenn ich mich richtig erinnere brauchten die BaseGameUtils einmal die Support-v4 Lib und die PlayServices und deine App wiederum die BaseGameUtils (ggf. auch noch die Support-v4)...
Musst mal ein bisschen probieren, oder möglichst 100%tig sicher sagen können wo der Fehler entsteht bzw wie er lautet.

Btw: In Eclipse bindet man die Libs so ein, dass man auf das Projekt-Paket rechts klickt > Preferences > Android > Libraries > Add (irgendwie so... und dann kannst du die verlinken - nutze seit Längerem IntelliJ, deswegen bin ich mir auch nicht mehr 100% tig sicher^^ - aber das findet man auch via Google)

Beste Grüße und viel Erfolg (kannst ja mal den Fehler reinkopieren)
Martin

Open Source

Antworten
FLX Apps
  • Forum-Beiträge: 13

05.12.2014, 13:35:26 via Website

Hi,

also ich hab gerade erst selbst mein erstes Spiel entwickelt, und bei mir scheiterte es auch zu Anfang daran. Mir hat der Tipp mit dem "make_eclipse_compat"-Skript damals allerdings weitergeholfen. Hast du Linux oder Windows? Je nachdem muss man wahrscheinlich make_eclipse_compat oder make_eclipse_compat.cmd ausführen. Führe die Datei jedenfalls einmal in der Konsole und nicht mit Doppelklick aus (das heißt, du öffnest die Konsole, bewegst dich in den Ordner ("cd [Pfad]") und führst sie dann halt dort aus ("./make_eclipse_compat" oder so was)). Eventuell werden dir dort ja weitere Hinweise ausgegeben.

Wenn das Skript jedenfalls funktioniert hat, so müsste sich im "android-basic-samples-master"-Ordner ein neuer Ordner namens "eclipse_compat" befinden. Dort unter "libraries" sind dann die Eclipse-kompatiblen BaseGameUtils. Diese konnte ich jedenfalls in Eclipse ganz normal als existierendes Android-Projekt importieren.

Die Google Play Services brauchst du auch. Die kannst du dir in Eclipse über den SDK-Manager runterladen und dann auf die gleiche Weise aus dem sdk-Ordner importieren (dazu gibt es aber auch haufenweise Anleitungen im Netz).

Nach Import der Projekte musst du sie jeweils als Library deklarieren (Rechtsklick - Properties - Android - Library - Is Library ankreuzen) und deinem Projekt hinzufügen (Rechtsklick - Properties - Android - Library - Add...).

Antworten
Heretsu
  • Forum-Beiträge: 37

05.12.2014, 15:06:23 via Website

Hallo ihr beiden, vielen Dank für eure Antworten.
Wenn ich die Datei mit cmd öffne, erscheint folgender Fehler:
\Scripts>if NOT exist BasicSamples (
echo "* Error: this script must be run from the base directory of your working
copy."
exit /B 1
)
"*
Error: this script must be run from the base directory of your working copy
."

Naja, anscheinend ist es auch nicht nötig. Ich habe gestern weiter gearbeitet und mittlerweile verbindet sich die App nun mit Google Play, vermute ich zumindest. Kann man das irgendwie überprüfen?
Wenn ich nun aber zur Activity gehe wo der Score in die Bestenliste(Leaderboard) übertragen werden soll, stürzt die App ab mit dem Fehler "A fatal developer error has ocurred..." Ich habe die Meta-Tags im Manifest bereits aktualisiert, wie es Google vorschlägt.
Liegt es vilt daran, dass ich was in dieser Activity vergessen habe? Da habe ich nämlich nur folgenden Befehl eingegeben:

Games.Leaderboards.submitScore(mGoogleApiClient,  getString(R.string.leaderboard_id), score);

und über der onCreate Methode dies:

private GoogleApiClient mGoogleApiClient;

MfG

Antworten
pepperonas
  • Forum-Beiträge: 434

05.12.2014, 23:00:33 via Website

Heretsu

Naja, anscheinend ist es auch nicht nötig. Ich habe gestern weiter gearbeitet und mittlerweile verbindet sich die App nun mit Google Play, vermute ich zumindest. Kann man das irgendwie überprüfen?

Ja, kann man.

Log.d("Logcat hilft", "mGoogleApiClient.isConnected(): " + (mGoogleApiClient.isConnected() ? "verbunden" : "NICHT verbunden"));

WICHTIG (darunter an 5ter Stelle auch besagte Methode)

Ich empfehle stark, dir vorher einen Überblick über die Methoden zu machen, einfach drauflos arbeiten, ist meiner Meinung nach (für das was du vor hast) mehr hinderlich als dass es zu sauberem und fehlerfreiem Code führt. Du bist letztlich auf die Features von GP angewiesen und hier frei-schnautze vorzugehen könnte zu Frust führen. :P (bitte nicht als Belehrung verstehen, sondern als gut gemeinten Rat) ;)

Open Source

Antworten
Heretsu
  • Forum-Beiträge: 37

06.12.2014, 21:00:23 via Website

Abend, füge ich den Log ein, startet die App nicht mehr :/ Also sie crasht beim starten.
Logcat zeigt folgendes:
12-06 20:56:49.128: W/asset(3708): Copying FileAsset 0x77a8ccb0 (zip:/data/app/com.og.quiz-1.apk:/resources.arsc) to buffer size 329572 to make it aligned.
12-06 20:56:49.249: I/dalvikvm-heap(3708): Grow heap (frag case) to 14.660MB for 8596816-byte allocation
12-06 20:56:49.389: W/dalvikvm(3708): threadid=1: thread exiting with uncaught exception (group=0x4163de18)
12-06 20:56:49.389: E/AndroidRuntime(3708): FATAL EXCEPTION: main
12-06 20:56:49.389: E/AndroidRuntime(3708): Process: com.og.quiz, PID: 3708
12-06 20:56:49.389: E/AndroidRuntime(3708): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.og.quiz/com.og.quiz.MyActivity}: java.lang.NullPointerException
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2585)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2641)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread.access$800(ActivityThread.java:156)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.os.Handler.dispatchMessage(Handler.java:102)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.os.Looper.loop(Looper.java:157)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread.main(ActivityThread.java:5867)
12-06 20:56:49.389: E/AndroidRuntime(3708): at java.lang.reflect.Method.invokeNative(Native Method)
12-06 20:56:49.389: E/AndroidRuntime(3708): at java.lang.reflect.Method.invoke(Method.java:515)
12-06 20:56:49.389: E/AndroidRuntime(3708): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
12-06 20:56:49.389: E/AndroidRuntime(3708): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
12-06 20:56:49.389: E/AndroidRuntime(3708): at dalvik.system.NativeStart.main(Native Method)
12-06 20:56:49.389: E/AndroidRuntime(3708): Caused by: java.lang.NullPointerException
12-06 20:56:49.389: E/AndroidRuntime(3708): at com.og.quiz.MyActivity.onCreate(MyActivity.java:35)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.Activity.performCreate(Activity.java:5312)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1111)
12-06 20:56:49.389: E/AndroidRuntime(3708): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2541)
12-06 20:56:49.389: E/AndroidRuntime(3708): ... 11 more

Edit: Die ResultActivity(wo der Score hochgeladen wird) crasht nun mit dem Fehler:
12-06 21:11:59.570: E/AndroidRuntime(6593): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.og.quiz/com.og.quiz.ResultActivity}: java.lang.IllegalArgumentException: GoogleApiClient parameter is required.

— geändert am 06.12.2014, 21:14:08

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.12.2014, 21:09:05 via Website

Poste mal bitte den Code aus

com.og.quiz.MyActivity.onCreate(MyActivity.java:35)

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Heretsu
  • Forum-Beiträge: 37

06.12.2014, 22:32:51 via Website

    package com.og.quiz;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.games.Games;
import com.google.android.gms.plus.Plus;
import com.google.example.games.basegameutils.BaseGameActivity;
import com.google.example.games.basegameutils.BaseGameUtils;

import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MyActivity extends BaseGameActivity
        implements ConnectionCallbacks, OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    private static final String DIALOG_ERROR = "dialog_error";
    private boolean mResolvingError = false;
    public MediaPlayer mp1, mp2;
    private SignInButton mSignInButton;
    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Log.d("Logcat hilft", "mGoogleApiClient.isConnected(): " + (mGoogleApiClient.isConnected() ? "verbunden" : "NICHT verbunden"));

        mp1 = MediaPlayer.create(MyActivity.this, R.raw.intro);//mp1 wird eine mp3 Datei zugeordnet, die sich im Ordner raw befindet
        mp2 = MediaPlayer.create(MyActivity.this, R.raw.klick);//mp2 wird eine mp3 Datei zugeordnet, die sich im Ordner raw befindet
        mp1.start();//mp1(Intromusik) wird beim öffnen der Activity geöffnet
        Button opt = (Button) findViewById(R.id.Button01);//Button vom Layout wird zugeordnet
        Button next = (Button) findViewById(R.id.button1);//Button vom Layout wird zugeordnet
        mSignInButton = (SignInButton) findViewById(R.id.sign_in_button);
        Button sign_out = (Button) findViewById(R.id.sign_out_button);
        next.setOnClickListener(new View.OnClickListener() { // Was passieren soll, wenn man auf den Button "next" klickt
        public void onClick(View view) {
               Intent intent = new Intent(view.getContext(), LevelActivity.class);//Activity FachbereichActivity wird als Intent ausgewählt
               startActivity(intent);// Intent von oben wird gestartet
              mp2.start();//mp2(Klickmusik wird gestartet)
                }});
       opt.setOnClickListener(new View.OnClickListener() {// Was passieren soll, wenn man auf den Button "opt" klickt
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), OptionsActivity.class);//Activity OptionsActivity wird als Intent ausgewählt
                startActivity(intent);// Intent von oben wird gestartet
                mp2.start();//mp2(Klickmusik wird gestartet)
                } });
       mSignInButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            mSignInClicked = true;
            mGoogleApiClient.connect();
               mp2.start();//mp2(Klickmusik wird gestartet)
               } }); 
       sign_out.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
         mSignInClicked = false;
         Games.signOut(mGoogleApiClient);
               mp2.start();//mp2(Klickmusik wird gestartet)
               } });


       mGoogleApiClient = new GoogleApiClient.Builder(this)
       .addConnectionCallbacks(this)
       .addOnConnectionFailedListener(this)
       .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
       .addApi(Games.API).addScope(Games.SCOPE_GAMES)
       // add other APIs and scopes here as needed
       .build();
       }


    @Override
    public void onConnected(Bundle connectionHint) {
        // Connected to Google Play services!
        // The good stuff goes here.
    }
    @Override
    public void onConnectionSuspended(int cause) {
         mGoogleApiClient.connect();}

    private static int RC_SIGN_IN = 9001;
    private boolean mResolvingConnectionFailure = false;
    private boolean mAutoStartSignInflow = true;
    private boolean mSignInClicked = false;
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        if (mResolvingConnectionFailure) {
            // already resolving
            return;
        }

        // if the sign-in button was clicked or if auto sign-in is enabled,
        // launch the sign-in flow
        if (mSignInClicked || mAutoStartSignInflow) {
            mAutoStartSignInflow = false;
            mSignInClicked = false;
            mResolvingConnectionFailure = true;

            // Attempt to resolve the connection failure using BaseGameUtils.
            // The R.string.signin_other_error value should reference a generic
            // error string in your strings.xml file, such as "There was
            // an issue with sign-in, please try again later."
            if (!BaseGameUtils.resolveConnectionFailure(this,
                    mGoogleApiClient, connectionResult,
                    RC_SIGN_IN, R.string.signin_other_error)) {
                mResolvingConnectionFailure = false;
            }
        }

        // Put code here to display the sign-in button
    }
    protected void onActivityResult(int requestCode, int resultCode,
            Intent intent) {
        if (requestCode == RC_SIGN_IN) {
            mSignInClicked = false;
            mResolvingConnectionFailure = false;
            if (resultCode == RESULT_OK) {
                mGoogleApiClient.connect();
            } else {
                // Bring up an error dialog to alert the user that sign-in
                // failed. The R.string.signin_failure should reference an error
                // string in your strings.xml file that tells the user they
                // could not be signed in, such as "Unable to sign in."
                BaseGameUtils.showActivityResultError(this,
                    requestCode, resultCode, R.string.signin_failure);
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
          // more about this later
            mGoogleApiClient.connect();
        }
    protected void onPause(){
        super.onPause();
        mp1.stop();
    }
    @Override
    protected void onStop() {
        super.onStop();
        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }


    @Override
    public void onSignInFailed() {
        // TODO Auto-generated method stub

    }


    @Override
    public void onSignInSucceeded() {
        // TODO Auto-generated method stub

    }
}

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.12.2014, 22:47:24 via App

Danke :)
Leider weiss ich nicht wo die betreffende Zeile ist

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Heretsu
  • Forum-Beiträge: 37

06.12.2014, 23:49:30 via Website

Update: Ich gehe stark davon aus, dass die App sich nicht verbindet.
Ich hab den Log Eintrag hier eingesetzt:

 public void onConnected(Bundle connectionHint)

Aber es wird nichts angezeigt. Außerdem habe ich folgendes in die ResultActivity hinzugefügt:

mGoogleApiClient = new GoogleApiClient.Builder(this)
       .addConnectionCallbacks(this)
       .addOnConnectionFailedListener(this)
       .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
       .addApi(Games.API).addScope(Games.SCOPE_GAMES)
       // add other APIs and scopes here as needed
       .build();

Und Logcat meldet mir nun den Fehler, dass GoogleApiClient connected sein muss.

Also gehe ich sehr stark davon aus, dass die App sich nicht verbindet. Nur warum?

Antworten
pepperonas
  • Forum-Beiträge: 434

07.12.2014, 05:16:00 via Website

Der Log führt natürlich zu einem Fehler, ich meine was denkst du was "mGoogleApiClient.isConnected()" macht?
Der Code vollzieht einen Zugriff auf das Objekt mGoogleApiClient <- wenn das "null" ist gibts den Nullptr.

Du greifst auf ein Objekt am Anfang von onCreate zu, dass du am Ende von onCreate lädst... Hmm... Wenn das für dich sinnvoll klingt solltest du mit den Java-Grundlagen weitermachen, oder (und das ist bessere Alternative) anfangen über den Ablauf deines Programm nachzudenken.

Kleiner Tipp: nimm dir mal ein Blatt Papier und male dir mal auf was du wie anlegen willst und was du wann brauchst*. Vor dem Bildschirm verliere ich gerne mal den Überblick, wenn es dir auch so geht (was sehr danach aussieht und nicht schlimm ist), sollte man sich Mittel und Wege überlegen diese Grundproblematiken in den Griff zu bekommen.

*je genauer du das machst, desto einfacher wird es beim Programmieren (trotzdem aufs Wesentliche beschränken).
Btw: wenn du erstmal 5 Minuten gar keinen Einfall hast, dann weißt du auch woher die Fehler aktuell kommen :D aber nicht aufgeben, weitermachen ;)

Und jetzt zum Code an sich:
-Kopiere mal den kompletten Code in Notepad und sichere ihn ab.
-zurück in Eclipse / And.Studio löscht du alle Kommentare und die Media Player Dinger raus (die brauchst du gerade nicht)
-als nächstes schreibst du die Klassendeklaration um in

public class MyActivity extends BaseGameActivity
        implements ConnectionCallbacks, OnConnectionFailedListener, View.onClickListener

{

-(ggf. mit großem "O" weiß nicht...)
-deine Button lädst du in onCreate mit

Button btnConnect = (Button) findbyid(....)
btnConnect.setonclicklistener(this);

-nun implementierst du die onClick-Methoden und setzt da deinen Code der Buttons rein
also

@Override onCLick(View v){
// deine Methoden die ausgeführt werden sollen wenn geklickt wurde

}

-füge weitere Logs den Funktionen hinzu zB Log.d("Main", "onConneceted erreicht!");
-was passiert bei onClick() wenn du das Programm testest?

— geändert am 07.12.2014, 05:26:27

Open Source

Antworten
Heretsu
  • Forum-Beiträge: 37

07.12.2014, 23:24:57 via Website

Hey, ich habe es hingekriegt :)
Die App verbindet sich nun mit den Servern von Google und der Highscore wird auch gespeichert!
Vielen Dank für eure Hilfe!
Eine Frage habe ich aber noch: Wie kann ich mehrere Bestenlisten anzeigen lassen? Zurzeit kann ich mit einem klick auf einen Button, eine Bestenliste anzeigen. Ich habe aber 4 Stück, wie mache ich das am besten?
Aktueller Code sieht so aus:

 else if(view.getId() == R.id.show_leaderboard){
            startActivityForResult(Games.Leaderboards.getLeaderboardIntent(
                getApiClient(), getString(R.string.int_id)), 
                1);

MfG

Antworten
pepperonas
  • Forum-Beiträge: 434

08.12.2014, 09:49:42 via Website

Super, das freut mich :)
Du könntest eine Art Spinner nehmen und dort klickt der Nutzer welche Liste er angezeigt haben will und nachdem er einen Button drückt, wird dann die jeweilige Liste angezeigt. Oder halt über vier Button - aber ob das so schön aussieht.. :P

Open Source

Antworten