Adding Saved Games to Your Android Game

This guide shows you how to use the Saved Games API in an Android application. The API can be found in the package.

Before you begin

If you haven't already done so, you might find it helpful to review the Saved Games game concepts.

Before you start to code using the Saved Games API:

public void onCreate(Bundle savedInstanceState) {


    // Create the Google API Client with access to Plus, Games, and Drive
    mGoogleApiClient = new GoogleApiClient.Builder(this)


Once the player is signed in and the GoogleApiClient is connected, your game can start using the Saved Games API.

Displaying Saved Games

You can integrate the Saved Games API wherever your game provides players with the option to save or restore their progress. Your game might display such an option at designated save/restore points or allow players to save or restore progress at any time.

Once players select the save/restore option in your game, your game should bring up a screen that prompts the players to enter information for a new saved game or select an existing saved game to restore. To simplify your development, the Saved Games API provides a default Saved Games selection user interface (UI) that you can use out-of-the-box. The Saved Games selection UI allows players to create a new saved game, view details about existing saved games, and load previous saved games.

To bring up the default Saved Games UI:

  1. Call getSelectSnapshotIntent() to get an Intent for launching the default Saved Games selection UI. In the method call, you can set boolean values in the allowAddButton and allowDelete parameters to indicate if your game wants the UI to provide buttons to create a new saved game or delete existing saved games.
  2. Call startActivityForResult() and pass in that Intent. If the call is successful, the game displays the Saved Game selection UI, along with the options you specified.

The following snippet shows how to bring up the default Saved Games selection UI:

private static final int RC_SAVED_GAMES = 9009;

private void showSavedGamesUI() {
    int maxNumberOfSavedGamesToShow = 5;
    Intent savedGamesIntent = Games.Snapshots.getSelectSnapshotIntent(mGoogleApiClient,
            "See My Saves", true, true, maxNumberOfSavedGamesToShow);
    startActivityForResult(savedGamesIntent, RC_SAVED_GAMES);

If the player selects to create a new saved game or load an existing saved game, the UI sends a request to Google Play games services. If the request is successful, Google Play games services returns a Snapshot object representing the saved game to your game through the onActivityResult() callback. Your game can override this callback to check if any errors occurred during request.

The following code snippet shows a sample implementation of onActivityResult():

private String mCurrentSaveName = "snapshotTemp";

 * This callback will be triggered after you call startActivityForResult from the
 * showSavedGamesUI method.
protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
    if (intent != null) {
        if (intent.hasExtra(Snapshots.EXTRA_SNAPSHOT_METADATA)) {
            // Load a snapshot.
            SnapshotMetadata snapshotMetadata = (SnapshotMetadata)
            mCurrentSaveName = snapshotMetadata.getUniqueName();

            // Load the game data from the Snapshot
            // ...
        } else if (intent.hasExtra(Snapshots.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
            // ...

Writing Saved Games

To store content to a saved game, your game must obtain a reference to a Snapshot object then call open() to get access to modify its contents. You can store a player's data in byte format by calling writeBytes().

Once all your modifications are made to the saved game's content or metadata, call commitAndClose() to send your changes to Google's servers. In the method call, your game can associate additional information to tell Google Play games services how to present this saved game to players. This information is represented in a SnapshotMetaDataChange object, which your game creates using SnapshotMetadataChange.Builder.

The following snippet shows how your game might commit changes to a saved game:

private PendingResult<Snapshots.CommitSnapshotResult> writeSnapshot(Snapshot snapshot,
        byte[] data, Bitmap coverImage, String desc) {

    // Set the data payload for the snapshot

    // Create the change operation
    SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()

    // Commit the operation
    return Games.Snapshots.commitAndClose(mGoogleApiClient, snapshot, metadataChange);

If the player's device is not connected to a network when your app calls commitAndClose(), Google Play games services stores the saved game data locally on the device. Upon device re-connection, Google Play games services syncs the locally cached saved game changes to Google's servers.

Loading Saved Games

To retrieve all saved games for the currently signed-in player, call the load() method.

Your game can also retrieve a specific saved game through the player's UI selection, as described in Displaying Saved Games. The returned saved game is represented as a Snapshot, which your game can then open to read its content and metadata.

To improve your game's performance, you are encouraged to perform saved game loading as a background operation rather than in the main thread. One way to do this is by using an AsyncTask and override its doInBackground() method to open the saved game.

The following snippet shows how you might implement the AsyncTask to load a specific saved game:

private byte[] mSaveGameData;

void loadFromSnapshot() {
    // Display a progress dialog
    // ...

    AsyncTask<Void, Void, Integer> task = new AsyncTask<Void, Void, Integer>() {
        protected Integer doInBackground(Void... params) {
            // Open the saved game using its name.
            Snapshots.OpenSnapshotResult result =,
                    mCurrentSaveName, true).await();

            // Check the result of the open operation
            if (result.getStatus().isSuccess()) {
                Snapshot snapshot = result.getSnapshot();
                // Read the byte content of the saved game.
                try {
                    mSaveGameData = snapshot.getSnapshotContents().readFully();
                } catch (IOException e) {
                    Log.e(TAG, "Error while reading Snapshot.", e);
            } else{
                Log.e(TAG, "Error while loading: " + result.getStatus().getStatusCode());

            return result.getStatus().getStatusCode();

        protected void onPostExecute(Integer status) {
            // Dismiss progress dialog and reflect the changes in the UI.
            // ...


Handling saved game conflicts

When using the Saved Games service in your game, it is possible for multiple devices to perform reads and writes on the same saved game. In the event that a device temporarily loses its network connection and later reconnects, this might cause data conflicts whereby the saved game stored on a player's local device is out-of-sync with the remote version stored in Google's servers. The Saved Games services provides a conflict resolution mechanism that presents both sets of conflicting saved games at read-time and lets you implement a resolution strategy that is appropriate for your game.

When Google Play games services detects a data conflict, it notifies your game during a saved game open operation by returning a status code of STATUS_SNAPSHOT_CONFLICT. In this event, the OpenSnapshotResult provides two versions of the saved game:

  • The most-up-to-date version known by Google Play games services to be accurate; and
  • A modified version detected on one of the player's devices that contains conflicting content or metadata. This may not be the same as the version that you tried to save.

Your game must decide how to resolve the conflict by picking one of the provided versions or merging the data of the two saved game versions.

To detect and resolve saved game conflicts, follow these steps:

  1. Call If STATUS_SNAPSHOT_CONFLICT is returned, you have a conflict to resolve.
  2. Call OpenSnapshotResult.getConflictId() to retrieve the conflict ID that uniquely identifies the detected conflict. Your game needs this value to send a conflict resolution request later.
  3. Call getConflictingSnapshot() to get the modified version.
  4. Call getSnapshot() to get the server version.
  5. To resolve the saved game conflict, select a version that you want to save to the server as the final version, and pass it to Snapshots.resolveConflict() method.

The following snippet shows and example of how your game might handle a saved game conflict by selecting the newest saved game as the final version to save:

private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 3;

 * Conflict resolution for when Snapshots are opened.  Must be run in an AsyncTask or in a
 * background thread,
Snapshot processSnapshotOpenResult(Snapshots.OpenSnapshotResult result, int retryCount) {
    Snapshot mResolvedSnapshot = null;

    int status = result.getStatus().getStatusCode();
    Log.i(TAG, "Save Result status: " + status);

    if (status == GamesStatusCodes.STATUS_OK) {
        return result.getSnapshot();
    } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
        return result.getSnapshot();
    } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
        Snapshot snapshot = result.getSnapshot();
        Snapshot conflictSnapshot = result.getConflictingSnapshot();

        // Resolve between conflicts by selecting the newest of the conflicting snapshots.
        mResolvedSnapshot = snapshot;

        if (snapshot.getMetadata().getLastModifiedTimestamp() <
                conflictSnapshot.getMetadata().getLastModifiedTimestamp()) {
            mResolvedSnapshot = conflictSnapshot;

        Snapshots.OpenSnapshotResult resolveResult = Games.Snapshots.resolveConflict(
                mGoogleApiClient, result.getConflictId(), mResolvedSnapshot).await();

        if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) {
            // Recursively attempt again
            return processSnapshotOpenResult(resolveResult, retryCount);
        } else {
            // Failed, log error and show Toast to the user
            String message = "Could not resolve snapshot conflicts";
            Log.e(TAG, message);
            Toast.makeText(getBaseContext(), message, Toast.LENGTH_LONG).show();


    // Fail, return null.
    return null;

Modifying a saved game for conflict resolution

If you want to merge data from the two Saved Games or modify an existing Snapshot to save to the server as the resolved final version, follow these steps:

  1. Pick a Snapshot object from getConflictingSnapshot() or getSnapshot() as your base.
  2. Next, call Snapshots.resolveConflict() and pass in the Snapshot that you selected in the previous step. This stores the Snapshot to the server.
  3. Call open() to retrieve the Snapshot that you just stored in the previous step. Now make your modifications to the returned Snapshot, then call Snapshots.commitAndClose() to upload the modified save game to the server.

Migrating from the AppState API

If your game uses the Cloud Save (AppState) API to store player data to Google Play games services, you should migrate your code to use the Saved Games API as soon as possible. The following table lists the code changes that you should be aware of when migrating your game:

Operation Cloud Save Saved Games
Setup In your Android.xml manifest, declare
  • In your Android.xml manifest, declare instead.
  • When creating your GoogleApiClient, you must specify Drive.SCOPE_APPFOLDER and Drive.API as the scope and API requested by your app.
Load Call AppStateManager.load(). Call
Save Call AppStateManager.update(). Call Snapshot.writeBytes() followed by Snapshots.commitAndClose().
Resolve conflict Call AppStateManager.resolve(). Call Snapshots.resolveConflict().

Enviar comentarios sobre…

Play Games Services for Android
Play Games Services for Android