Following the deprecation of the
[Google Sign-In](https://android-developers.googleblog.com/2024/09/streamlining-android-authentication-credential-manager-replaces-legacy-apis.html)
API, we are removing the games v1 SDK in 2026. After February 2025, you will be unable to publish
titles that are newly integrated with games v1 SDK, on Google Play. We recommend that you use the
games v2 SDK instead.  

While existing titles with the previous games v1 integrations continue to function for a
couple of years, you are encouraged to
[migrate to v2](https://developer.android.com/games/pgs/android/migrate-to-v2)
starting June 2025.  

This guide is for using the Play Games Services v1 SDK. The C++ SDK for
Play Games Services v2 is not yet available.

This guide shows you how to save and load a player's game progress data using
the Saved Games service in a C++ application. You can use this
service to automatically load and save player game progress at any point
during gameplay. This service can also enable players to trigger a user
interface to update or restore an existing save game, or create a new one.

## Before you begin

If you haven't already done so, you might find it helpful to review the
[Saved Games game concepts](https://developer.android.com/games/pgs/savedgames).

Before you start to code using the Saved Games API:

- [Install the C++ Play Games SDK](https://developer.android.com/games/pgs/downloads#sdk).
- [Set up your C++ development environment](https://developer.android.com/games/pgs/v1/cpp).
- [Download and review the C++ code sample](https://github.com/playgameservices/).
- [Enable the Saved Games service in the Google Play Console](https://developer.android.com/games/pgs/console/enable-features#enable_saved_games).

## Data formats and cross-platform compatibility

Saved Games data that you save to Google's servers must be in
`std::vector<uint8_t>` format. The Saved Games service takes care of encoding
your data for cross-platform compatibility; Android applications can read in
this same data as a byte array without any cross-platform compatibility issues.

Avoid using platform-specific formats when choosing a data format for your
Saved Games data. We strongly encourage you to use a data format, like
XML or JSON, that has strong library support on multiple platforms.

## Enable the Saved Games service

Before you can use the Saved Games service, you must first enable access to
it. To do so, call `EnableSnapshots()` when you create the service with
`gpg::GameServices::Builder`. This will enable the additional auth scopes
required by Saved Games at the next auth event.

## Display Saved Games

In your game, you can provide an option that players can trigger to save or
restore saved games. When players select this option, your game should bring
up a screen that displays existing save slots, and allow players to either
save to or load from one of these slots, or create a new saved game. Use the
following method to do so:  

      SnapshotManager::ShowSelectUIOperation(...)

The Saved Games selection UI allows
players to create a new saved game, view details about existing saved games,
and load previous save games.  

      SnapshotManager::SnapshotSelectUIResponse response;
      if (IsSuccess(response.status)) {
      if (response.data.Valid()) {
        LogI("Description: %s", response.data.Description().c_str());
        LogI("FileName %s", response.data.FileName().c_str());
        //Opening the snapshot data
        ...
      } else {
        LogI("Creating new snapshot");
        ...
      }
    } else {
      LogI("ShowSelectUIOperation returns an error %d", response.status);
    }

The following example illustrates how to bring up the default Saved Games UI
and handle the player's UI selection:  

      service_->Snapshots().ShowSelectUIOperation(
      ALLOW_CREATE_SNAPSHOT,
      ALLOW_DELETE_SNAPSHOT,
      MAX_SNAPSHOTS,
      SNAPSHOT_UI_TITLE,
      [this](gpg::SnapshotManager::SnapshotSelectUIResponse const & response) {
      ...
          }

If, in the example above, `ALLOW_CREATE_SNAPSHOT` is `true` and `MAX_SNAPSHOTS`
is greater than the actual number of snapshots that the user has currently
created, the default Snapshot UI provides players with a button to create a new
save game, rather than selecting an existing one. (When displayed, the button
is at the bottom of the UI.) When a player clicks on this button, the
`SnapshotSelectUIResponse` response is valid but has no data.

## Open and read saved games

To access a saved game and read or modify its contents, first open
the `SnapshotMetadata` object representing that saved game. Next, call the
`SnapshotManager::Read*()` method.

The following example shows how to open a saved game:  

      LogI("Opening file");
      service_->Snapshots()
      .Open(current_snapshot_.FileName(),
                   gpg::SnapshotConflictPolicy::BASE_WINS,
            [this](gpg::SnapshotManager::OpenResponse const & response) {
               LogI("Reading file");
               gpg::SnapshotManager::ReadResponse responseRead =
               service_->Snapshots().ReadBlocking(response.data);
              ...
            }

## Detect and resolve data conflicts

When you open a `SnapshotMetadata` object, the Saved Games service detects
whether a conflicting saved game exists. Data conflicts might occur when the saved
game stored on a player's local device is out-of-sync with the remote version
stored in Google's servers.

The conflict policy you specify when opening a saved game tells the Saved
Games service how to automatically resolve a data conflict.
The policy can be one of the following:

| Conflict Policy | Description |
|---|---|
| `SnapshotConflictPolicy::MANUAL` | Indicates that the Saved Games service should perform no resolution action. Instead, your game will perform a [custom merge](https://developer.android.com/games/pgs/v1/cpp/saved-games#custom-merge). |
| `SnapshotConflictPolicy::LONGEST_PLAYTIME` | Indicates the Saved Games service should pick the saved game with the largest play time value. |
| `SnapshotConflictPolicy::BASE_WINS` | Indicates the Saved Games service should pick the base saved game. |
| `SnapshotConflictPolicy::REMOTE_WINS` | Indicates the Saved Games service should pick the remote saved game. The remote version is a version of the saved game that is detected on one of the player's devices and has a more recent timestamp than the base version. |

If you specified a conflict policy other than `GPGSnapshotConflictPolicyManual`,
the Saved Games service will merge the saved game and return the updated version
through the resulting `SnapshotManager::OpenResponse` value. Your game can open
the saved game, write to it, then call the SnapshotManager::Commit(...)
method to commit the saved game to Google's servers.

### Perform a custom merge

If you specified `SnapshotConflictPolicy::MANUAL` as the conflict policy,
your game must resolve any data conflict detected before performing further
read or write operations on the saved game.

In this case, when a data conflict is detected, the service returns the
following parameters through `SnapshotManager::OpenResponse`:

- A `conflict_id` to uniquely identify this conflict (you will use this value when committing the final version of the saved game);
- The conflicting base version of the saved game; and,
- The conflicting remote version of the saved game.

Your game must decide what data to save, then call the
`SnapshotManager::ResolveConflictBlocking()` method to commit/resolve the final
version to Google's servers.  

        //Resolve conflict
        gpg::SnapshotManager::OpenResponse resolveResponse =
            manager.ResolveConflictBlocking(openResponse.conflict_base, metadata_change,
                                      openResponse.conflict_id);

## Write saved games

To write a saved game, first open the `SnapshotMetadata` object representing
that saved game, resolve any data conflicts detected, then call the
`SnapshotManager::Commit()` method to commit your saved
game changes.
| **Note:** You can only perform a commit operation after opening a saved game (that is, when `SnapshotMetadata.isOpen` is `true`). Once committed, the saved game is immediately closed and must be reopened to be committed again.

The following example shows how you might create a change and commit a
saved game.

1. First, open the snapshot we want to edit, and make sure all conflicts are
   resolved by choosing the base.

       service_->Snapshots().Open(
             file_name,
             gpg::SnapshotConflictPolicy::BASE_WINS,
             [this](gpg::SnapshotManager::OpenResponse const &response) {
               if (IsSuccess(response.status)) {
                 // metadata : gpg::SnapshotMetadata
                 metadata = response.data;
               } else {
                 // Handle snapshot open error here
               }
             });

2. Next, create a saved game change that includes the image data used for the
   cover image:

       gpg::SnapshotMetadataChange::Builder builder;
       gpg::SnapshotMetadataChange metadata_change =
           builder.SetDescription("CollectAllTheStar savedata")
                    .SetCoverImageFromPngData(pngData).Create();

3. Finally, commit the saved game changes.

       gpg::SnapshotManager::CommitResponse commitResponse =
           service_->Snapshots().CommitBlocking(metadata, metadata_change, SetupSnapshotData());

   The data parameter contains all of the save game data that you are storing.
   The change also contains additional saved game metadata, such as time
   played and a description for the saved game.

If the commit operation completed successfully, players can see
the saved game in the Saved Games selection UI.