在您的游戏中集成 PGS 召回 API

此页面介绍如何在您的游戏中实现 召回 API。它首先介绍如何设置您的游戏服务器和客户端以支持 API,然后介绍如何存储和检索令牌。

游戏服务器设置

设置您的游戏服务器以对 Google 服务器进行召回 API 调用。

1. 设置您的 Play 游戏服务项目

(如果尚未完成) 请按照 设置 Google Play 游戏服务 中的说明操作。

2. 为游戏设置服务帐号

请按照 创建服务帐号 中的说明操作。最后,您应该会获得一个包含服务帐号凭据的 JSON 文件。

3. 下载 PlayGamesServices 的服务器端 Java 库

下载最新的 google-api-services-games 库 并将其上传到您的服务器。

4. 为召回 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();

游戏客户端设置

设置您的游戏客户端以检索您的服务器用于与 Google 服务器通信的召回会话 ID。

Java SDK

在您的客户端中设置 Java SDK,并确保在您的 gradle 文件中包含 com.google.android.gms:play-services-games-v2:19.0.0com.google.android.gms:play-services-tasks:18.0.2 或更高版本。

要使用正确的信息与 Google 的服务器通信,您需要从客户端 SDK 请求召回会话 ID,然后将其发送到您的游戏服务器。

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 请求召回会话 ID,并将其发送到您的游戏服务器。

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

在您的游戏服务器中使用召回 API

配置服务器和客户端后,您可以将来自游戏客户端的 recallSessionID 发送到您的游戏服务器,并按照以下指南开始使用 Java API 在服务器端存储、检索或删除召回令牌。

存储令牌

可以使用 LinkPersonaRequest 对象存储用户的角色和游戏令牌。您需要使用 GoogleCredential 调用 Google API(有关上下文,请参阅 调用 Google API)。请注意,根据 1:1 基数约束,您一次只能将一个角色链接到一个 PGS 个人资料(反之亦然)。如果此 PGS 个人资料已链接到另一个角色,则应设置解析策略。

或者,您可以选择在令牌上设置 TTL,该令牌使用 Durations 对象声明令牌的有效期。您可以选择使用 SetTtl()(如下所示)进行设置,该方法根据方法中指定的时间量设置过期日期,或者使用 setExpireTime(),该方法允许您设置令牌过期的确切时间。

您必须加密角色和游戏令牌,并且它们不能包含个人身份信息。角色和令牌字符串最多可以包含 256 个字符,并且每个玩家每个游戏最多可以存储 20 个令牌或角色。

在给定时间,每个角色每个玩家只能存储一个令牌。尝试使用相同的角色存储另一个令牌将覆盖原始令牌。

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
}

检索令牌

根据游戏的需求,有三种选项可以检索令牌。您可以请求以下内容

  • 与当前游戏关联的令牌,包括游戏范围内的召回令牌。
  • 开发人员帐户拥有的所有游戏中存储的最后一个令牌。
  • 给定开发人员帐户拥有的游戏列表,与每个游戏关联的所有召回令牌。

游戏范围内的召回令牌

要从当前游戏中检索召回令牌,请从客户端获取 recallSessionId 并将其传递到 retrieveTokens API 中

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
}

开发人员帐户拥有的所有游戏中最新的召回令牌

要检索 Google Play Console 中开发人员帐户拥有的所有游戏中存储的最新令牌,您需要从客户端获取 recallSessionId 并将其传递到 lastTokenFromAllDeveloperGames API 中,如以下代码片段所示。作为响应的一部分,您可以检查与此令牌关联的 应用程序 ID

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 并将其传递到 gamesPlayerTokens API 中。提供 应用程序 ID 列表。

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.
}

删除召回令牌

如果需要,您还可以使用以下调用删除召回令牌

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();

启用无个人资料模式

您可以通过以下步骤为没有 PGS 个人资料的用户启用 有限的召回 API 功能

  1. 在 Play 开发者控制台中为您的 PGS 游戏项目启用无个人资料召回。 选择标记为“打开存储”的选项。
  2. 查看本节后面介绍的 其他条款
  3. 将以下元数据标签添加到您的 应用程序清单
<meta-data
  android:name="com.google.android.gms.games.PROFILELESS_RECALL_ENABLED"
  android:value="true" />

其他条款

除了受 Play 游戏服务服务条款 的约束外,您还同意,如果您对没有 PGS 个人资料的用户使用召回 API(这使得能够在没有 Play 游戏服务个人资料的情况下与 Google 共享最终用户的数据),则您必须在与 Google 共享此类数据之前,向最终用户提供适当的通知,描述 1) 您与 Google 共享数据以启用 Play 游戏的帐户链接功能,2) 设置以管理此类共享的可用性,例如通过 Play 游戏设置提供的设置,以及 3) 根据 Google 隐私权政策 处理此类数据,并获得符合所有适用法律要求的此类共享的适当最终用户同意。