Nach der Einstellung der Google-Anmeldung-API wird das games v1 SDK im Jahr 2026 entfernt. Ab Februar 2025 kannst du bei Google Play keine Titel mehr veröffentlichen, die neu in Games SDK V1 integriert wurden. Wir empfehlen, stattdessen das Games SDK V2 zu verwenden.
Bestehende Titel mit den vorherigen Integrationen für Spiele v1 funktionieren zwar noch einige Jahre, aber wir empfehlen Ihnen, ab Juni 2025 zu Version 2 zu migrieren.
In diesem Leitfaden wird die Verwendung des Play Games Services SDK V1 beschrieben. Informationen zur neuesten SDK-Version finden Sie in der Dokumentation zu Version 2.
In diesem Leitfaden erfahren Sie, wie Sie gespeicherte Spiele mit der Snapshots API von Google Play-Spieldienste implementieren. Die APIs finden Sie in den Paketen com.google.android.gms.games.snapshot
und com.google.android.gms.games
.
Hinweis
Falls Sie es noch nicht getan haben, sollten Sie sich mit den Grundlagen für gespeicherte Spiele vertraut machen.
- Aktivieren Sie die Unterstützung für gespeicherte Spiele für Ihr Spiel in der Google Play Console.
- Laden Sie das Codebeispiel für gespeicherte Spiele auf der Android-Beispielseite herunter und sehen Sie es sich an.
- Machen Sie sich mit den Empfehlungen in der Qualitätscheckliste vertraut.
Snapshots-Client abrufen
Bevor Sie die Snapshots API verwenden können, muss Ihr Spiel zuerst ein SnapshotsClient
-Objekt abrufen. Rufen Sie dazu die Methode Games.getSnapshotsClient()
auf und übergeben Sie die Aktivität und die GoogleSignInAccount
für den aktuellen Spieler. Informationen zum Abrufen der Spieler-Kontoinformationen finden Sie unter Anmeldung in Android-Spielen.
Drive-Bereich angeben
Die Snapshots API nutzt die Google Drive API zum Speichern von gespeicherten Spielen. Damit Ihre App auf die Drive API zugreifen kann, muss sie beim Erstellen des Google-Anmeldeclients den Bereich Drive.SCOPE_APPFOLDER
angeben.
Hier ist ein Beispiel dafür, wie Sie dies in der Methode onResume()
für Ihre Anmeldeaktivität tun können:
private GoogleSignInClient mGoogleSignInClient; @Override protected void onResume() { super.onResume(); signInSilently(); } private void signInSilently() { GoogleSignInOptions signInOption = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN) // Add the APPFOLDER scope for Snapshot support. .requestScopes(Drive.SCOPE_APPFOLDER) .build(); GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption); signInClient.silentSignIn().addOnCompleteListener(this, new OnCompleteListener<GoogleSignInAccount>() { @Override public void onComplete(@NonNull Task<GoogleSignInAccount> task) { if (task.isSuccessful()) { onConnected(task.getResult()); } else { // Player will need to sign-in explicitly using via UI } } }); }
Gespeicherte Spiele anzeigen
Sie können die Snapshots API überall dort einbinden, wo Spieler in Ihrem Spiel die Möglichkeit haben, ihren Fortschritt zu speichern oder wiederherzustellen. In Ihrem Spiel wird eine solche Option möglicherweise an bestimmten Speicher-/Wiederherstellungspunkten angezeigt oder Spieler können den Fortschritt jederzeit speichern oder wiederherstellen.
Sobald Spieler die Option zum Speichern/Wiederherstellen in Ihrem Spiel auswählen, kann Ihr Spiel optional einen Bildschirm aufrufen, auf dem Spieler aufgefordert werden, Informationen für ein neues gespeichertes Spiel einzugeben oder ein vorhandenes gespeichertes Spiel zum Wiederherstellen auszuwählen.
Um die Entwicklung zu vereinfachen, bietet die Snapshots API eine standardmäßige Benutzeroberfläche für die Auswahl gespeicherter Spiele, die Sie sofort verwenden können. Über die Benutzeroberfläche für die Auswahl gespeicherter Spiele können Spieler ein neues gespeichertes Spiel erstellen, Details zu vorhandenen gespeicherten Spielen aufrufen und frühere gespeicherte Spiele laden.
So starten Sie die Standard-UI für gespeicherte Spiele:
- Rufen Sie
SnapshotsClient.getSelectSnapshotIntent()
auf, um eineIntent
zum Starten der Standard-UI für die Auswahl gespeicherter Spiele abzurufen. - Rufen Sie
startActivityForResult()
auf und übergeben Sie dieIntent
. Wenn der Aufruf erfolgreich ist, wird im Spiel die Benutzeroberfläche zur Auswahl gespeicherter Spiele zusammen mit den von dir angegebenen Optionen angezeigt.
Hier ist ein Beispiel für den Start der Standard-UI für die Auswahl gespeicherter Spiele:
private static final int RC_SAVED_GAMES = 9009; private void showSavedGamesUI() { SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(this)); int maxNumberOfSavedGamesToShow = 5; Task<Intent> intentTask = snapshotsClient.getSelectSnapshotIntent( "See My Saves", true, true, maxNumberOfSavedGamesToShow); intentTask.addOnSuccessListener(new OnSuccessListener<Intent>() { @Override public void onSuccess(Intent intent) { startActivityForResult(intent, RC_SAVED_GAMES); } }); }
Wenn der Spieler ein neues gespeichertes Spiel erstellt oder ein vorhandenes gespeichertes Spiel lädt, sendet die Benutzeroberfläche eine Anfrage an die Google Play-Spieldienste. Wenn die Anfrage erfolgreich ist, geben die Google Play-Spieldienste Informationen zurück, mit denen das gespeicherte Spiel über den onActivityResult()
-Callback erstellt oder wiederhergestellt werden kann. Ihr Spiel kann diesen Callback überschreiben, um zu prüfen, ob während der Anfrage Fehler aufgetreten sind.
Das folgende Code-Snippet zeigt eine Beispielimplementierung von onActivityResult()
:
private String mCurrentSaveName = "snapshotTemp"; /** * This callback will be triggered after you call startActivityForResult from the * showSavedGamesUI method. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (intent != null) { if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) { // Load a snapshot. SnapshotMetadata snapshotMetadata = intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA); mCurrentSaveName = snapshotMetadata.getUniqueName(); // Load the game data from the Snapshot // ... } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) { // Create a new snapshot named with a unique string String unique = new BigInteger(281, new Random()).toString(13); mCurrentSaveName = "snapshotTemp-" + unique; // Create the new snapshot // ... } } }
Gespeicherte Spiele schreiben
So speicherst du Inhalte in einem gespeicherten Spiel:
- Snapshot asynchron über
SnapshotsClient.open()
öffnen Rufen Sie dann dasSnapshot
-Objekt aus dem Ergebnis der Aufgabe ab, indem SieSnapshotsClient.DataOrConflict.getData()
aufrufen. - Rufen Sie eine
SnapshotContents
-Instanz überSnapshotsClient.SnapshotConflict
ab. - Rufen Sie
SnapshotContents.writeBytes()
auf, um die Daten des Spielers im Byteformat zu speichern. - Wenn alle Änderungen geschrieben wurden, rufen Sie
SnapshotsClient.commitAndClose()
auf, um die Änderungen an die Server von Google zu senden. Im Methodenaufruf kann Ihr Spiel optional zusätzliche Informationen angeben, um den Google Play-Spielediensten mitzuteilen, wie dieses gespeicherte Spiel den Spielern präsentiert werden soll. Diese Informationen werden in einemSnapshotMetaDataChange
-Objekt dargestellt, das von Ihrem Spiel mitSnapshotMetadataChange.Builder
erstellt wird.
Das folgende Snippet zeigt, wie Ihr Spiel Änderungen an einem gespeicherten Spiel vornehmen kann:
private Task<SnapshotMetadata> writeSnapshot(Snapshot snapshot, byte[] data, Bitmap coverImage, String desc) { // Set the data payload for the snapshot snapshot.getSnapshotContents().writeBytes(data); // Create the change operation SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder() .setCoverImage(coverImage) .setDescription(desc) .build(); SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(this)); // Commit the operation return snapshotsClient.commitAndClose(snapshot, metadataChange); }
Wenn das Gerät des Spielers nicht mit einem Netzwerk verbunden ist, wenn Ihre App SnapshotsClient.commitAndClose()
aufruft, speichern die Google Play-Spieldienste die gespeicherten Spieldaten lokal auf dem Gerät. Wenn das Gerät wieder verbunden wird, synchronisiert Google Play-Spieldienste die lokal zwischengespeicherten Änderungen am gespeicherten Spiel mit den Google-Servern.
Gespeicherte Spiele laden
So rufen Sie gespeicherte Spiele für den aktuell angemeldeten Spieler ab:
- Snapshot asynchron über
SnapshotsClient.open()
öffnen Rufen Sie dann dasSnapshot
-Objekt aus dem Ergebnis der Aufgabe ab, indem SieSnapshotsClient.DataOrConflict.getData()
aufrufen. Alternativ kann Ihr Spiel auch einen bestimmten Snapshot über die Auswahl-UI für gespeicherte Spiele abrufen, wie unter Gespeicherte Spiele anzeigen beschrieben. - Rufen Sie die
SnapshotContents
-Instanz überSnapshotsClient.SnapshotConflict
ab. - Rufen Sie
SnapshotContents.readFully()
auf, um den Inhalt des Snapshots zu lesen.
Das folgende Snippet zeigt, wie Sie ein bestimmtes gespeichertes Spiel laden können:
Task<byte[]> loadSnapshot() { // Display a progress dialog // ... // Get the SnapshotsClient from the signed in account. SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(this)); // In the case of a conflict, the most recently modified version of this snapshot will be used. int conflictResolutionPolicy = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED; // Open the saved game using its name. return snapshotsClient.open(mCurrentSaveName, true, conflictResolutionPolicy) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "Error while opening Snapshot.", e); } }).continueWith(new Continuation<SnapshotsClient.DataOrConflict<Snapshot>, byte[]>() { @Override public byte[] then(@NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception { Snapshot snapshot = task.getResult().getData(); // Opening the snapshot was a success and any conflicts have been resolved. try { // Extract the raw data from the snapshot. return snapshot.getSnapshotContents().readFully(); } catch (IOException e) { Log.e(TAG, "Error while reading Snapshot.", e); } return null; } }).addOnCompleteListener(new OnCompleteListener<byte[]>() { @Override public void onComplete(@NonNull Task<byte[]> task) { // Dismiss progress dialog and reflect the changes in the UI when complete. // ... } }); }
Konflikte bei gespeicherten Spielen beheben
Wenn Sie die Snapshots API in Ihrem Spiel verwenden, können mehrere Geräte Lese- und Schreibvorgänge für dasselbe gespeicherte Spiel ausführen. Wenn ein Gerät vorübergehend die Netzwerkverbindung verliert und sich später wieder verbindet, kann dies zu Datenkonflikten führen. Das auf dem lokalen Gerät eines Spielers gespeicherte gespeicherte Spiel ist dann nicht mit der Remote-Version auf den Google-Servern synchronisiert.
Die Snapshots API bietet einen Mechanismus zur Konfliktlösung, der beide Sätze von in Konflikt stehenden gespeicherten Spielen zur Lesezeit präsentiert und es Ihnen ermöglicht, eine für Ihr Spiel geeignete Lösungsstrategie zu implementieren.
Wenn die Google Play-Spieldienste einen Datenkonflikt erkennen, gibt die Methode SnapshotsClient.DataOrConflict.isConflict()
den Wert true
zurück. In diesem Fall stellt die Klasse SnapshotsClient.SnapshotConflict
zwei Versionen des gespeicherten Spiels bereit:
- Serverversion: Die aktuelle Version, die von Google Play-Spieldiensten als korrekt für das Gerät des Spielers erkannt wird.
- Lokale Version: Eine geänderte Version, die auf einem der Geräte des Spielers erkannt wurde und in der es zu Konflikten mit Inhalten oder Metadaten kommt. Das kann eine andere Version sein als die, die Sie speichern wollten.
Ihr Spiel muss entscheiden, wie der Konflikt behoben werden soll. Dazu kann es eine der bereitgestellten Versionen auswählen oder die Daten der beiden gespeicherten Spielversionen zusammenführen.
So erkennen und beheben Sie Konflikte bei gespeicherten Spielen:
- Rufen Sie
SnapshotsClient.open()
an. Das Ergebnis der Aufgabe enthält eineSnapshotsClient.DataOrConflict
-Klasse. - Rufen Sie die Methode
SnapshotsClient.DataOrConflict.isConflict()
auf. Wenn das Ergebnis „true“ ist, müssen Sie einen Konflikt beheben. - Rufen Sie
SnapshotsClient.DataOrConflict.getConflict()
auf, um eineSnapshotsClient.snapshotConflict
-Instanz abzurufen. - Rufen Sie
SnapshotsClient.SnapshotConflict.getConflictId()
auf, um die Konflikt-ID abzurufen, die den erkannten Konflikt eindeutig identifiziert. Ihr Spiel benötigt diesen Wert, um später eine Anfrage zur Konfliktlösung zu senden. - Rufen Sie
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
auf, um die lokale Version zu erhalten. - Rufen Sie
SnapshotsClient.SnapshotConflict.getSnapshot()
auf, um die Serverversion abzurufen. - Um den Konflikt mit dem gespeicherten Spiel zu beheben, wählen Sie eine Version aus, die Sie als endgültige Version auf dem Server speichern möchten, und übergeben Sie sie an die Methode
SnapshotsClient.resolveConflict()
.
Das folgende Snippet zeigt ein Beispiel dafür, wie dein Spiel einen Konflikt mit einem gespeicherten Spiel behandeln kann, indem es das zuletzt geänderte gespeicherte Spiel als endgültige Version zum Speichern auswählt:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; Task<Snapshot> processSnapshotOpenResult(SnapshotsClient.DataOrConflict<Snapshot> result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSource<Snapshot> source = new TaskCompletionSource<>(); source.setResult(result.getData()); return source.getTask(); } // There was a conflict. Try resolving it by selecting the newest of the conflicting snapshots. // This is the same as using RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED as a conflict resolution // policy, but we are implementing it as an example of a manual resolution. // One option is to present a UI to the user to choose which snapshot to resolve. SnapshotsClient.SnapshotConflict conflict = result.getConflict(); Snapshot snapshot = conflict.getSnapshot(); Snapshot conflictSnapshot = conflict.getConflictingSnapshot(); // Resolve between conflicts by selecting the newest of the conflicting snapshots. Snapshot resolvedSnapshot = snapshot; if (snapshot.getMetadata().getLastModifiedTimestamp() < conflictSnapshot.getMetadata().getLastModifiedTimestamp()) { resolvedSnapshot = conflictSnapshot; } return Games.getSnapshotsClient(theActivity, GoogleSignIn.getLastSignedInAccount(this)) .resolveConflict(conflict.getConflictId(), resolvedSnapshot) .continueWithTask( new Continuation< SnapshotsClient.DataOrConflict<Snapshot>, Task<Snapshot>>() { @Override public Task<Snapshot> then( @NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception { // Resolving the conflict may cause another conflict, // so recurse and try another resolution. if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) { return processSnapshotOpenResult(task.getResult(), retryCount + 1); } else { throw new Exception("Could not resolve snapshot conflicts"); } } }); }
Gespeicherte Spiele zur Konfliktlösung ändern
Wenn Sie Daten aus mehreren gespeicherten Spielen zusammenführen oder eine vorhandene Snapshot
ändern möchten, um sie als endgültige Version auf dem Server zu speichern, gehen Sie so vor:
- Rufen Sie
SnapshotsClient.open()
an . - Rufen Sie
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
auf, um ein neuesSnapshotContents
-Objekt zu erhalten. - Führen Sie die Daten aus
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
undSnapshotsClient.SnapshotConflict.getSnapshot()
in dasSnapshotContents
-Objekt aus dem vorherigen Schritt ein. - Optional: Erstellen Sie eine
SnapshotMetadataChange
-Instanz, wenn sich die Metadatenfelder ändern. - Rufen Sie
SnapshotsClient.resolveConflict()
an. Übergeben Sie in Ihrem MethodenaufrufSnapshotsClient.SnapshotConflict.getConflictId()
als erstes Argument und die ObjekteSnapshotMetadataChange
undSnapshotContents
, die Sie zuvor geändert haben, als zweites bzw. drittes Argument. - Wenn der
SnapshotsClient.resolveConflict()
-Aufruf erfolgreich ist, speichert die API dasSnapshot
-Objekt auf dem Server und versucht, das Snapshot-Objekt auf Ihrem lokalen Gerät zu öffnen.- Bei einem Konflikt gibt
SnapshotsClient.DataOrConflict.isConflict()
true
zurück. In diesem Fall sollte Ihr Spiel zu Schritt 2 zurückkehren und die Schritte wiederholen, um den Snapshot zu ändern, bis die Konflikte behoben sind. - Wenn kein Konflikt besteht, gibt
SnapshotsClient.DataOrConflict.isConflict()
false
zurück und dasSnapshot
-Objekt kann von Ihrem Spiel geändert werden.
- Bei einem Konflikt gibt