In diesem Leitfaden erfahren Sie, wie Sie gespeicherte Spiele mithilfe der
Snapshots API, die von den Google Play-Spieldiensten bereitgestellt wird. Die APIs finden Sie in der
com.google.android.gms.games.snapshot
und com.google.android.gms.games
Pakete.
Hinweis
Falls Sie dies noch nicht getan haben, kann es hilfreich sein, sich die Konzepte für „Gespeicherte Spiele“
- Achte darauf, die Unterstützung für gespeicherte Spiele zu aktivieren. für dein Spiel in der Google Play Console.
- Laden Sie das Codebeispiel für gespeicherte Spiele in der Android-Beispielseite
- Machen Sie sich mit den im Artikel Checkliste für die Qualität
Snapshot-Client abrufen
Damit Sie die Snapshots API verwenden können, muss Ihr Spiel zuerst eine
SnapshotsClient
-Objekt. Rufen Sie dazu die Methode
Games.getSnapshotsClient()
und übergeben die
Aktivität und GoogleSignInAccount
für den aktuellen Spieler. Wenn Sie mehr darüber erfahren möchten, wie Sie
Informationen zum Spielerkonto abrufen, siehe
Anmeldung in Android-Spielen
Drive-Bereich angeben
Die Snapshots API nutzt die Google Drive API für den gespeicherten Spielspeicher. Bis
auf die Drive API zugreifen, muss in Ihrer App die
Drive.SCOPE_APPFOLDER
beim Erstellen des Google Log-in-Clients.
Hier ist ein Beispiel, wie Sie dies im
onResume()
für Ihre Anmeldeaktivitäten:
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 werden angezeigt
Du kannst die Snapshots API dort einbinden, wo dein Spiel Spielern die Option, den Fortschritt zu speichern oder wiederherzustellen. Möglicherweise wird in deinem Spiel Option an festgelegten Speicher-/Wiederherstellungspunkten oder erlauben Sie Spielern, Fortschritte zu erzielen.
Sobald Spieler die Option zum Speichern/Wiederherstellen in Ihrem Spiel ausgewählt haben, kann Ihr Spiel optional einen Bildschirm aufrufen, in dem die Spieler Informationen für ein neues gespeichertes oder ein gespeichertes Spiel zum Wiederherstellen auswählen.
Die Snapshots API bietet einen standardmäßigen Nutzer für die Auswahl gespeicherter Spiele, um die Entwicklung zu vereinfachen die Sie sofort verwenden können. Über die Benutzeroberfläche zur Auswahl gespeicherter Spiele ein neues gespeichertes Spiel erstellen, Details zu vorhandenen gespeicherten Spielen anzeigen und frühere gespeicherte Spiele laden.
So starten Sie die Standardbenutzeroberfläche für gespeicherte Spiele:
- Rufen Sie unter
SnapshotsClient.getSelectSnapshotIntent()
an, um eineIntent
zum Starten der Standardeinstellung Benutzeroberfläche zur Auswahl gespeicherter Spiele startActivityForResult()
anrufen und übergeben SieIntent
. Wenn der Anruf erfolgreich ist, zeigt das Spiel die Benutzeroberfläche zur Auswahl des gespeicherten Spiels sowie mit den von Ihnen angegebenen Optionen.
Hier ein Beispiel für den Start der Standardoberfläche 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 erstellen oder ein vorhandenes Spiel laden möchte,
die UI eine Anfrage
an die Google Play-Spieldienste sendet. Ist die Anfrage erfolgreich,
Die Google Play-Spieldienste geben Informationen zum Erstellen oder Wiederherstellen des gespeicherten Spiels über
onActivityResult()
Callback des Nutzers an. Dein Spiel kann diesen Callback überschreiben, um zu prüfen, ob bei der Anfrage Fehler aufgetreten sind.
Das folgende Code-Snippet zeigt eine Beispielimplementierung eines
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 speichern Sie Inhalte in einem gespeicherten Spiel:
- Öffnet einen Snapshot asynchron über
SnapshotsClient.open()
. Rufen Sie dann das ObjektSnapshot
ab. durch Aufrufen vonSnapshotsClient.DataOrConflict.getData()
aus dem Ergebnis der Aufgabe. - Rufen Sie eine
SnapshotContents
-Instanz überSnapshotsClient.SnapshotConflict
ab. - Rufe
SnapshotContents.writeBytes()
auf, um die Daten des Spielers im Byteformat zu speichern. - Sobald alle Änderungen geschrieben sind, rufen Sie
SnapshotsClient.commitAndClose()
, um Ihre Änderungen an die Google-Server zu senden. Im Methodenaufruf kann dein Spiel optional zusätzliche Informationen bereitstellen, die den Google Play-Spieldiensten mitteilen, wie sie dieses gespeicherte Spiel Spielern präsentieren. Diese Informationen werden in einemSnapshotMetaDataChange
-Element dargestellt. -Objekt, das vom 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 Players nicht mit einem Netzwerk verbunden ist, wenn Ihre App einen Anruf durchführt
SnapshotsClient.commitAndClose()
, die Google Play-Spieldienste speichern die gespeicherten Spieldaten lokal auf
auf dem Gerät. Sobald das Gerät wieder verbunden ist, synchronisieren die Google Play-Spieldienste das lokal im Cache gespeicherte Spiel.
auf den Google-Servern.
Gespeicherte Spiele werden geladen
So rufen Sie gespeicherte Spiele des aktuell angemeldeten Spielers ab:
- Öffnet einen Snapshot asynchron über
SnapshotsClient.open()
. Rufen Sie dann das ObjektSnapshot
ab. durch Aufrufen vonSnapshotsClient.DataOrConflict.getData()
aus dem Ergebnis der Aufgabe. Alternativ kann Ihr Ein Spiel kann auch einen bestimmten Snapshot über die Benutzeroberfläche für die Auswahl gespeicherter Spiele abrufen. Dies wird unter Gespeicherte Spiele anzeigen - 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. // ... } }); }
Umgang mit gespeicherten Spielkonflikten
Wenn Sie die Snapshots API in Ihrem Spiel verwenden, Lese- und Schreibzugriffe auf dasselbe Spiel ausgeführt werden. Für den Fall, dass ein die Netzwerkverbindung des Geräts vorübergehend getrennt und sich später wieder verbindet, kann dies Datenkonflikte verursachen, bei denen das gespeicherte Spiel auf dem lokalen Gerät eines Spielers gespeichert ist. nicht synchron mit der Remote-Version ist, die auf den Google-Servern gespeichert ist.
Die Snapshots API bietet einen Konfliktlösungsmechanismus, der sowohl Gruppen von in Konflikt stehenden gespeicherten Spielen zur Lesezeit und ermöglicht es Ihnen, eine Auflösung zu implementieren. die zu deinem Spiel passt.
Wenn die Google Play-Spieldienste einen Datenkonflikt feststellen,
Die Methode SnapshotsClient.DataOrConflict.isConflict()
gibt den Wert true
zurück. In diesem Fall
Die Klasse SnapshotsClient.SnapshotConflict
bietet zwei Versionen des gespeicherten Spiels:
- Serverversion: Dies ist die aktuellste Version, die den Google Play-Spieldiensten für ihre Genauigkeit bekannt ist. für das Gerät des Spielers, und
- Lokale Version: Eine modifizierte Version, die auf einem der Geräte des Players erkannt wurde und die folgende Inhalte enthält: widersprüchlichen Inhalten oder Metadaten. Dies ist möglicherweise nicht die Version, die Sie speichern wollten.
Dein Spiel muss entscheiden, wie der Konflikt gelöst werden soll, indem du eine der oder die Daten der beiden gespeicherten Spielversionen zusammenführen.
So erkennen und lösen Sie Konflikte bei gespeicherten Spielen:
- Rufen Sie
SnapshotsClient.open()
auf. Das Ergebnis der Aufgabe enthält die KlasseSnapshotsClient.DataOrConflict
. - Rufen Sie die Methode
SnapshotsClient.DataOrConflict.isConflict()
auf. Wenn das Ergebnis "true" ist, zu lösen. - Rufen Sie
SnapshotsClient.DataOrConflict.getConflict()
auf, um eineSnaphotsClient.snapshotConflict
-Instanz. - Rufen Sie
SnapshotsClient.SnapshotConflict.getConflictId()
auf, um die Konflikt-ID abzurufen, die eindeutig identifiziert den erkannten Konflikt. Dein Spiel benötigt diesen Wert, um eine Anfrage zur Konfliktlösung zu senden . - Rufen Sie
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
auf, um die lokale Version abzurufen. - Rufen Sie
SnapshotsClient.SnapshotConflict.getSnapshot()
auf, um die Serverversion abzurufen. - Um den Konflikt mit dem gespeicherten Spiel zu lösen, wähle eine Version aus, die du auf dem Server als
der finalen Version und übergeben Sie sie an die Methode
SnapshotsClient.resolveConflict()
.
Das folgende Snippet zeigt und beispielhaft, wie in Ihrem Spiel ein Konflikt mit einem gespeicherten Spiel behandelt werden könnte, indem Sie Das zuletzt geänderte gespeicherte Spiel wird als endgültige Version zum Speichern ausgewählt:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; TaskS<napshot >processSnapshotOpenResult(SnapshotsClient.DataOrConflictS<napshot >result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSourceS<napshot >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.DataOrConflictS<napshot,> TaskS<napshot(>>) { @Override public TaskS<napshot >then( @NonNull TaskS<napshotsClient.DataOrConflictS<napshot >>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(C"ould not resolve snapshot conflicts)"; } } }); }
Gespeicherte Spiele zur Konfliktlösung ändern
Wenn du Daten aus mehreren gespeicherten Spielen zusammenführen oder ein vorhandenes Snapshot
ändern möchtest
um sie als aufgelöste endgültige Version auf dem Server zu speichern:
- Rufen Sie
SnapshotsClient.open()
auf . - Rufen Sie unter
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
an, um ein neuesSnapshotContents
-Objekt. - Führen Sie die Daten aus
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
undSnapshotsClient.SnapshotConflict.getSnapshot()
in dasSnapshotContents
-Objekt aus dem vorherigen Schritt. - Erstellen Sie optional eine
SnapshotMetadataChange
-Instanz, wenn Änderungen an den Metadaten vorgenommen wurden . - Rufen Sie
SnapshotsClient.resolveConflict()
auf. In Ihrem Methodenaufruf übergeben SieSnapshotsClient.SnapshotConflict.getConflictId()
als erstes Argument und derSnapshotMetadataChange
- undSnapshotContents
-Objekte, die Sie zuvor als zweites und jeweils ein drittes Argument. - Wenn der
SnapshotsClient.resolveConflict()
-Aufruf erfolgreich ist, speichert die APISnapshot
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 dieser sollte das Spiel zu Schritt 2 zurückkehren und die Schritte zum Ändern der Momentaufnahme bis zum Konflikte gelöst werden. - Wenn kein Konflikt vorliegt, gibt
SnapshotsClient.DataOrConflict.isConflict()
false
und DasSnapshot
-Objekt ist geöffnet und kann von Ihrem Spiel geändert werden.
- Bei einem Konflikt gibt