Интегрируйте PGS Recall API в игру

В этой статье рассказывается, как реализовать Recall API в игре. Сначала мы расскажем, как настроить игровой сервер и клиент для поддержки API, а затем объясним, как хранить и получать токены.

Настройка игрового сервера

Настройте игровой сервер так, чтобы он мог выполнять вызовы Recall API к серверам Google.

1. Как настроить проект сервисов Play Games

Если вы ещё этого не сделали, следуйте инструкциям в статье Как настроить игровые сервисы Google Play.

2. Настройте сервисный аккаунт для игры.

Следуйте инструкциям по созданию сервисного аккаунта. В результате у вас должен быть файл JSON с учетными данными сервисного аккаунта.

3. Скачать серверную библиотеку Java для PlayGamesServices

Скачайте библиотеку google-api-services-games и загрузите ее на свой сервер.

4. Как подготовить учетные данные для вызовов Recall API

Подробнее о том, как подготовить авторизованный вызов API…

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.games.Games;
import com.google.api.services.games.GamesScopes;

// ...

GoogleCredential credential =
  GoogleCredential.fromStream(new FileInputStream("<credentials>.json"))
    .createScoped(Collections.singleton(GamesScopes.ANDROIDPUBLISHER));

Games gamesApi =
    new Games.Builder(httpTransport, JSON_FACTORY, credential).build();

Настройка игрового клиента

Настройте игровой клиент так, чтобы он получал идентификаторы сеансов Recall, которые ваш сервер использует для связи с серверами Google.

Java SDK

Настройте Java SDK в клиенте и добавьте com.google.android.gms:play-services-games-v2:19.0.0 и com.google.android.gms:play-services-tasks:18.0.2 или более позднюю версию в файл Gradle.

Чтобы передавать на серверы Google правильную информацию, вам нужно запросить у клиентского SDK идентификатор сеанса Recall и отправить его на сервер игры.

Kotlin

PlayGames.getRecallClient(getActivity())
                .requestRecallAccess()
                .addOnSuccessListener { recallAccess -> val recallSessionId: String = recallAccess.getSessionId() }
                // Send the recallSessionId to your game server

Java

PlayGames.getRecallClient(getActivity())
  .requestRecallAccess()
  .addOnSuccessListener(
    recallAccess -> {
      String recallSessionId = recallAccess.getSessionId();
      // Send the recallSessionId to your game server
    });

Unity SDK

Если вы ещё этого не сделали, настройте Unity SDK в своем клиенте.

Чтобы передавать на серверы Google правильную информацию, запросите у клиентского SDK идентификатор сеанса Recall и отправьте его на сервер игры.

PlayGamesPlatform.Instance.RequestRecallAccess(
    recallAccess => {
        string recallSessionId = recallAccess.sessionId;
        // Send the recallSessionId to your game server
    });

Нативный SDK версии 2 (бета)

Если вы ещё этого не сделали, начните работу с сервисами Play Games для C и C++.

// Include the following headers

#include "play_games.h"
#include "recall_client.h"
#include "pgs_status_code.h"
// Request Recall Access
// Initializes the Play Games Services v2 Native SDK (beta).
Pgs_initialize(javaVM, activity);

//Creating Recall Client
PgsRecallClient* pgs_recall_client =
      PgsRecallClient_create(activity);

// RequestRecallAccess Function
PgsRecallClient_requestRecallAccess(
    pgs_recall_client,

    // This is your callback function defined as an inline lambda
    [](PgsStatusCode status_code, char* session_id, user_data) {

        if (status_code == PGS_STATUS_SUCCESS) {
            // Recall Session Id Fetched Successfully
        } else {
            // Fetching Recall Session Id Failed
            // Handle error based on status_code.
            // Examples:
            // PGS_STATUS_NETWORK_ERROR: Check internet connection.
            // PGS_STATUS_INTERNAL_ERROR: An unexpected error occurred.
        }

        // Clean up the client instance passed as user_data
        PgsRecallClient* client = static_cast<PgsRecallClient*>(user_data);
        if (client != nullptr) {
            PgsRecallClient_destroy(client);
        }
    },

    user_data // Data to pass to the callback
);

// Shuts down the Play Games Services v2 Native SDK (beta).
Pgs_destroy()

Как использовать Recall API на сервере игры

После настройки сервера и клиента вы можете отправить recallSessionID из клиента игры на сервер игры и следовать приведенным ниже инструкциям, чтобы начать использовать Java API для хранения, извлечения или удаления токенов Recall на стороне сервера.

Токены магазинов

Аккаунт игрока в Google Play Games Recall API состоит из двух частей:

  • персонаж, который служит постоянным идентификатором аккаунта в игре;
  • токен, который служит ключом для безопасного входа игрока в аккаунт.

Вы можете сохранить образ и токен пользователя с помощью объекта LinkPersonaRequest. Используйте GoogleCredential для вызова API Google (подробнее см. в разделе Вызов API Google). Для персонажа действует ограничение на количество элементов 1:1: в профиле PGS может быть только один персонаж, а персонаж может принадлежать только одному профилю PGS. Задайте правила разрешения конфликтов, чтобы определить, как должны разрешаться нарушения ограничения на количество элементов 1:1.

При необходимости задайте срок действия токена. Используйте SetTtl() с объектом Durations, чтобы задать срок хранения, или укажите точное время окончания срока действия с помощью setExpireTime().

Токены персонажа и игры должны быть зашифрованы и не должны содержать информацию, позволяющую идентифицировать личность. Строки с персонажами и токенами могут содержать не более 256 символов.

import com.google.api.services.games.Games.Recall.LinkPersona;
import com.google.api.services.games.model.LinkPersonaRequest;
import com.google.api.services.games.model.LinkPersonaResponse;
import com.google.protobuf.util.Durations;

// ...

Games gamesApi =
    new Games.Builder(httpTransport, JSON_FACTORY, credential).build();

String recallSessionId = ... // recallSessionID from game client
String persona = ... // encrypted opaque string, stable for in-game account
String token = ... // encrypted opaque string encoding the progress line

LinkPersonaRequest linkPersonaRequest =
  LinkPersonaRequest.newBuilder()
    .setSessionId(recallSessionId)
    .setPersona(persona)
    .setToken(token)
    .setCardinalityConstraint(ONE_PERSONA_TO_ONE_PLAYER)
    .setConflictingLinksResolutionPolicy(CREATE_NEW_LINK)
    .setTtl(Durations.fromDays(7)) // Optionally set TTL for token
    .build();

LinkPersonaResponse linkPersonaResponse =
  gamesApi.recall().linkPersona(linkPersonaRequest).execute();

if (linkPersonaResponse.getState() == LINK_CREATED) {
  // success
}

Получение токенов

Получить токен можно тремя способами. Выберите тот, который подходит для вашей игры. Вы можете запросить:

  • Токены, связанные с текущей игрой, включая токены отзыва на уровне игры.
  • Последний токен, сохраненный во всех играх, принадлежащих аккаунту разработчика.
  • Возвращает все токены Recall, связанные с каждой игрой из списка, который принадлежит аккаунту разработчика.

Токены переноса для игр

Чтобы получить токены Recall из текущей игры, запросите recallSessionId у клиента и передайте его в API retrieveTokens:

import com.google.api.services.games.Games;
import com.google.api.services.games.model.RetrievePlayerTokensResponse;
import com.google.api.services.games.model.RecallToken;

// ...

String recallSessionId = ... // recallSessionID from game client

RetrievePlayerTokensResponse retrievePlayerTokensResponse =
  gamesApi.recall().retrieveTokens(recallSessionId).execute();

for (RecallToken recallToken : retrievePlayerTokensResponse.getTokens()) {
  String token recallToken.getToken();
  // Same string as was written in LinkPersona call
  // decrypt and recover in-game account
}

Последний токен Recall во всех играх, принадлежащих аккаунту разработчика

Чтобы получить последний токен, сохраненный во всех играх, принадлежащих аккаунту разработчика в Google Play Console, вам нужно получить recallSessionId от клиента и передать его в lastTokenFromAllDeveloperGames API, как показано в следующем фрагменте кода. В ответе вы можете проверить идентификатор приложения, связанный с этим токеном.

import com.google.api.services.games.Games;
import com.google.api.services.games.model.RetrieveDeveloperGamesLastPlayerTokenResponse;
import com.google.api.services.games.model.GamePlayerToken;
import com.google.api.services.games.model.RecallToken;

// ...

String recallSessionId = ... // recallSessionID from game client

RetrieveDeveloperGamesLastPlayerTokenResponse response =
        gamesApi.recall().lastTokenFromAllDeveloperGames(recallSessionId)
        .execute();

if (response.hasGamePlayerToken()) {
    GamePlayerToken gamePlayerToken = response.getGamePlayerToken();

    // The ID of the application that the token is associated with.
    String applicationId = gamePlayerToken.getApplicationId();

    // Same string as was written in LinkPersona call.
    RecallToken recallToken = gamePlayerToken.getRecallToken();

    // Decrypt and recover in-game account.
}

Все токены отзыва для списка игр, принадлежащих аккаунту разработчика.

Чтобы получить все токены, связанные со списком игр, которые принадлежат вашему аккаунту разработчика в Google Play Console, получите recallSessionId от клиента и передайте его в API gamesPlayerTokens. Укажите список идентификаторов приложений.

import com.google.api.services.games.Games;
import com.google.api.services.games.model.RetrieveGamesPlayerTokensResponse;
import com.google.api.services.games.model.GamePlayerToken;
import com.google.api.services.games.model.RecallToken;

// ...

String recallSessionId = ... // recallSessionID from game client

// Application IDs for which you would like to retrieve the recall tokens.
List<String> applicationIds = ...

RetrieveGamesPlayerTokensResponse response =
gamesApiClient
        .recall()
        .gamesPlayerTokens(recallSessionId)
        .setApplicationIds(applicationIds)
        .execute();

for (GamePlayerToken gamePlayerToken : response.getGamePlayerTokens()) {
    // The ID of the application that the token is associated with.
    String applicationId  = gamePlayerToken.getApplicationId();

    // Same string as was written in LinkPersona call.
    RecallToken recallToken = gamePlayerToken.getRecallToken();

    // Decrypt and recover in-game account.
}

Удалить токен отзыва

При необходимости вы также можете удалить токен Recall с помощью следующего вызова:

import com.google.api.services.games.Games;
import com.google.api.services.games.model.UnlinkPersonaRequest;
import com.google.api.services.games.model.UnlinkPersonaResponse;

// ...

String recallSessionId = ...
String persona = ...
String token = ...

Games gamesApi =
    new Games.Builder(httpTransport, JSON_FACTORY, credential).build();

UnlinkPersonaRequest unlinkPersonaRequest =
  UnlinkPersonaRequest.newBuilder()
    .setSessionId(recallSessionId)
    .setPersona(persona)
    // .setToken(token) - alternatively set token, but not both
    .build();

UnlinkPersonaResponse unlinkPersonaResponse =
  gamesApi.recall().unlinkPersona(unlinkPersonaRequest).execute();

boolean unlinked = unlinkPersonaResponse.isUnlinked();

Включить режим без профиля

Чтобы включить ограниченную функциональность Recall API для пользователей без профилей игровых сервисов Google Play, выполните следующие действия:

  1. Включите возврат без профиля для проекта игры в PGS в Play Console. Выберите &quot;Включить хранилище&quot;.
  2. Ознакомьтесь с дополнительными условиями, описанными далее в этом разделе.
  3. Добавьте в манифест приложения следующий тег метаданных:
<meta-data
  android:name="com.google.android.gms.games.PROFILELESS_RECALL_ENABLED"
  android:value="true" />

Дополнительные условия

Вы также должны соблюдать Условия использования сервисов Play Games. Если вы используете Recall API для пользователей без профиля PGS, что подразумевает передачу данных конечных пользователей в Google, вы должны перед передачей этих данных в Google предоставить конечным пользователям соответствующее уведомление, в котором описывается следующее:

  • Как вы делитесь данными с Google, чтобы включить функцию связывания аккаунтов Play Игр.
  • Доступность настроек для управления передачей данных, например в настройках Google Play Игр.
  • Обработка этих данных в соответствии с Политикой конфиденциальности Google и требование получить согласие конечного пользователя на передачу данных, соответствующее всем действующим юридическим требованиям.