Google Play Games Services创建新Snapshot的技术求助及代码疑问
How to Create a New Snapshot for Google Play Games Saved Games (Updated for Current API)
Hey there! I totally get how frustrating it is when official docs are vague and sample code is outdated (5 years is an eternity in Android development!). Let's walk through exactly how to create a new Snapshot using the current Google Play Games Services API, replacing that deprecated code.
First: Replace Deprecated onActivityResult with Activity Result API
The old onActivityResult method is no longer recommended—Android now uses the Activity Result Contracts API for handling activity results. Here's how to set up the launcher for Saved Games UI:
import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import com.google.android.gms.games.SnapshotsClient; import com.google.android.gms.games.snapshot.SnapshotMetadata; // Initialize this in your Activity/Fragment's onCreate private final ActivityResultLauncher<Intent> savedGamesLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK && result.getData() != null) { Intent intent = result.getData(); if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) { // Trigger creation of a new snapshot createNewSnapshot(); } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) { // Load existing snapshot (updated for current API) SnapshotMetadata metadata = intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA); mCurrentSaveName = metadata.getUniqueName(); loadExistingSnapshot(mCurrentSaveName); } } } );
Step-by-Step: Creating a New Snapshot
Now, let's fill in the createNewSnapshot() method—this is what replaces that // Create the new snapshot comment in your old code:
import com.google.android.gms.games.Games; import com.google.android.gms.games.snapshot.Snapshot; import com.google.android.gms.games.snapshot.SnapshotConflict; import com.google.android.gms.games.snapshot.SnapshotMetadataChange; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.Date; import java.util.Random; private void createNewSnapshot() { // 1. Generate a unique name for your new snapshot (same logic as your old code) String uniqueSnapshotName = "snapshotTemp-" + new BigInteger(281, new Random()).toString(13); // 2. Build metadata for the snapshot (display name, description, etc.) SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder() .setDisplayName("My Latest Save") // Name users will see in Saved Games UI .setDescription("Auto-saved on " + new Date()) // Optional: Set a cover image with .setCoverImage(bitmap) .build(); // 3. Get the SnapshotsClient (make sure user is signed in first!) SnapshotsClient snapshotsClient = Games.getSnapshotsClient( this, GoogleSignIn.getLastSignedInAccount(this) ); // 4. Open the snapshot (create it if it doesn't exist) snapshotsClient.open( uniqueSnapshotName, true, // Allow creating a new snapshot if it doesn't exist SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED // Handle conflicts automatically (or customize) ).addOnSuccessListener(snapshotOrConflict -> { if (snapshotOrConflict.isConflict()) { // Optional: Handle conflicts if multiple versions exist resolveSnapshotConflict(snapshotOrConflict); } else { // 5. Get the snapshot instance to write your game data Snapshot snapshot = snapshotOrConflict.getSnapshot(); // 6. Write your game state to the snapshot // Use try-with-resources to auto-close the output stream try (OutputStream outputStream = snapshot.getContents().getOutputStream()) { // Example: Write a JSON string of your game state String gameState = "{\"score\": 150, \"currentLevel\": 7, \"unlockedItems\": [\"shield\", \"double_jump\"]}"; outputStream.write(gameState.getBytes()); } catch (IOException e) { Log.e("SavedGames", "Error writing game data to snapshot", e); return; } // 7. Commit the changes and close the snapshot snapshotsClient.commitAndClose(snapshot, metadataChange) .addOnSuccessListener(voidResult -> { mCurrentSaveName = uniqueSnapshotName; Log.d("SavedGames", "New snapshot created successfully: " + uniqueSnapshotName); // Optional: Update UI to reflect the new save }) .addOnFailureListener(e -> { Log.e("SavedGames", "Failed to commit snapshot", e); }); } }).addOnFailureListener(e -> { Log.e("SavedGames", "Failed to open new snapshot", e); }); } // Optional: Handle snapshot conflicts (e.g., if user saved on multiple devices) private void resolveSnapshotConflict(SnapshotConflict conflict) { // For simplicity, we'll choose the most recently modified snapshot Snapshot resolvedSnapshot = conflict.getSnapshot(); SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder() .setDisplayName(resolvedSnapshot.getMetadata().getDisplayName()) .build(); SnapshotsClient snapshotsClient = Games.getSnapshotsClient( this, GoogleSignIn.getLastSignedInAccount(this) ); snapshotsClient.resolveConflict(conflict.getConflictId(), resolvedSnapshot, metadataChange) .addOnSuccessListener(voidResult -> { Log.d("SavedGames", "Snapshot conflict resolved successfully"); }) .addOnFailureListener(e -> { Log.e("SavedGames", "Failed to resolve snapshot conflict", e); }); }
Key Notes to Remember
- Sign-In Check: Always ensure the user is signed into Google Play Games before accessing
SnapshotsClient—add a check forGoogleSignIn.getLastSignedInAccount(this) != nullto avoid crashes. - Data Format: You can write any data format (JSON, Protobuf, binary) to the snapshot—just make sure you can read it back consistently when loading.
- Conflict Resolution: The example uses
RESOLUTION_POLICY_MOST_RECENTLY_MODIFIEDto auto-resolve conflicts, but you can implement custom logic if needed (e.g., let the user choose which save to keep). - Permissions: Make sure your app has the
com.google.android.gms.games.permission.SAVE_GAMESpermission in yourAndroidManifest.xml.
内容的提问来源于stack exchange,提问作者Houcine




