我们建议您对玩家进行身份验证,并安全地将玩家的身份传递到后端服务器。这使您的游戏能够安全地检索玩家的身份和其他数据,而不会在通过设备时暴露于潜在的篡改。
在这种情况下,一旦玩家成功登录,您可以从 Play 游戏服务 v2 SDK 请求一个特殊的单次使用代码(称为服务器身份验证代码),客户端将其传递给服务器。然后,在服务器上,将服务器身份验证代码交换为 OAuth 2.0 令牌,服务器可以使用该令牌调用 Google Play 游戏服务 API。
有关在游戏中添加登录的更多指导,请参阅Android 游戏的登录。
脱机访问需要以下步骤
- 在 Google Play Console 中:为你的游戏服务器创建凭据。凭据的 OAuth 客户端类型将为“网络”。
- 在 Android 应用中:作为登录的一部分,为服务器的凭据请求服务器身份验证代码,并将其传递给服务器。
- 在你的游戏服务器上:使用 Google 身份验证服务将服务器身份验证代码交换为 OAuth 访问令牌,然后使用它调用 Play 游戏服务的REST API。
开始之前
您首先需要在Google Play Console中添加你的游戏,如设置 Google Play 游戏服务中所述,并将Play 游戏服务登录与你的游戏集成。
创建服务器端 Web 应用
Google Play 游戏服务不提供 Web 游戏的后端支持。但是,它确实为你的 Android 游戏的服务器提供了后端服务器支持。
如果要在你的服务器端应用中使用Google Play 游戏服务的 REST API,请按照以下步骤操作
- 在Google Play Console中,选择一个游戏。
- 转到Play 游戏服务 > 设置和管理 > 配置。
- 选择添加凭据以转到添加凭据页面。选择游戏服务器作为凭据类型,然后继续到授权部分。
- 如果你的游戏服务器已拥有 OAuth 客户端 ID,请从下拉菜单中选择它。保存更改后,转到下一部分。
- 如果你的游戏服务器没有现有的 OAuth 客户端 ID,可以创建一个。
- 点击创建 OAuth 客户端,然后点击创建 OAuth 客户端 ID链接。
- 这将带你到 Google Cloud Platform 的与你的游戏关联的项目的创建 OAuth 客户端 ID页面。
- 填写页面的表单并点击创建。确保将应用程序类型设置为 Web 应用程序。
- 返回到添加凭据页面的授权部分,选择新创建的 OAuth 客户端并保存更改。
获取服务器身份验证代码
要检索游戏可用于后端服务器上的访问令牌的服务器身份验证代码
从客户端调用
requestServerSideAccess
。- 确保使用为游戏服务器注册的 OAuth 客户端 ID,而不是 Android 应用程序的 OAuth 客户端 ID。
- (可选)如果你的游戏服务器需要对 Play 游戏服务的脱机访问(使用刷新令牌的长期访问),可以将 forceRefreshToken 参数设置为 true。
GamesSignInClient gamesSignInClient = PlayGames.getGamesSignInClient(this); gamesSignInClient .requestServerSideAccess(OAUTH_2_WEB_CLIENT_ID, /* forceRefreshToken= */ false) .addOnCompleteListener( task -> { if (task.isSuccessful()) { String serverAuthToken = task.getResult(); // Send authentication code to the backend game server to be // exchanged for an access token and used to verify the player // via the Play Games Services REST APIs. } else { // Failed to retrieve authentication code. } });
将 OAuth 身份验证代码令牌发送到后端服务器,以便对其进行交换,根据 Play 游戏服务 REST API 验证玩家 ID,然后使用你的游戏进行身份验证。
发送服务器身份验证代码
将服务器身份验证代码发送到后端服务器以交换访问和刷新令牌。使用访问令牌代表玩家调用 Play 游戏服务 API,并选择性地存储刷新令牌以在访问令牌过期时获取新的访问令牌。
以下代码片段显示了如何在 Java 编程语言中实现服务器端代码以将服务器身份验证代码交换为访问令牌。它使用clientserverskeleton 示例应用。
/**
* Exchanges the authcode for an access token credential. The credential
* is the associated with the given player.
*
* @param authCode - the non-null authcode passed from the client.
* @param player - the player object which the given authcode is
* associated with.
* @return the HTTP response code indicating the outcome of the exchange.
*/
private int exchangeAuthCode(String authCode, Player player) {
try {
// The client_secret.json file is downloaded from the Google API
// console. This is used to identify your web application. The
// contents of this file shouldn't be shared.
//
File secretFile = new File("client_secret.json");
// If we don't have the file, we can't access any APIs, so return
// an error.
if (!secretFile.exists()) {
log("Secret file : " + secretFile
.getAbsolutePath() + " does not exist!");
return HttpServletResponse.SC_FORBIDDEN;
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
JacksonFactory.getDefaultInstance(), new
FileReader(secretFile));
// Extract the application id of the game from the client id.
String applicationId = extractApplicationId(clientSecrets
.getDetails().getClientId());
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
HTTPTransport,
JacksonFactory.getDefaultInstance(),
"https://oauth2.googleapis.com/token",
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
authCode,
"")
.execute();
log("hasRefresh == " + (tokenResponse.getRefreshToken() != null));
log("Exchanging authCode: " + authCode + " for token");
Credential credential = new Credential
.Builder(BearerToken.authorizationHeaderAccessMethod())
.setJsonFactory(JacksonFactory.getDefaultInstance())
.setTransport(HTTPTransport)
.setTokenServerEncodedUrl("https://www.googleapis.com/oauth2/v4/token")
.setClientAuthentication(new HttpExecuteInterceptor() {
@Override
public void intercept(HttpRequest request)
throws IOException {
}
})
.build()
.setFromTokenResponse(tokenResponse);
player.setCredential(credential);
// Now that we have a credential, we can access the Games API.
PlayGamesAPI api = new PlayGamesAPI(player, applicationId,
HTTPTransport, JacksonFactory.getDefaultInstance());
// Call the verify method, which checks that the access token has
// access to the Games API, and that the Player ID used by the
// client matches the playerId associated with the accessToken.
boolean ok = api.verifyPlayer();
// Call a Games API on the server.
if (ok) {
ok = api.updatePlayerInfo();
if (ok) {
// persist the player.
savePlayer(api.getPlayer());
}
}
return ok ? HttpServletResponse.SC_OK :
HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
} catch (IOException e) {
e.printStackTrace();
}
return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
从服务器调用 REST API
请参阅Google Play 游戏服务的 REST API,以全面了解可用的 API 调用。
以下是一些你可能觉得有用的 REST API 调用的示例
玩家
想要获取已登录玩家的 ID 和个人资料数据?使用'me'
作为 ID 调用Players.get。
好友
请参阅好友指南了解详细信息。
要检索玩家的好友列表,请使用
friends_all
作为collection
调用Players.list。要验证您是否有权访问好友列表,请使用
me
作为playerID
调用 Players.get,并在响应中查看profileSettings.friendsListVisibility
字段。
成就
有关详细信息,请参阅 成就 指南。
要获取当前成就列表,请调用 AchievementDefinitions.list。
将其与对 Achievements.list 的调用结合起来,以找出玩家解锁了哪些成就。
调用 Achievements.unlock 以解锁玩家成就。
调用 Achievements.increment 报告成就的进度,并了解玩家是否解锁了它。
如果您正在调试尚未投入生产的游戏,则可以从管理 API 调用 Achievements.reset 或 Achievements.resetAll,将成就重置为其原始状态。
排行榜
有关详细信息,请参阅 排行榜 指南。
想要获取游戏中所有记分板的列表?请调用 Leaderboards.list。
如果玩家完成了游戏,您可以将其分数提交到 Scores.submit 并了解它是否为新的高分。
要显示排行榜,请从 Scores.list 获取数据并将其显示给用户。
使用 Scores.listWindow 查找接近用户高分的各种分数。
要获取有关玩家在特定排行榜中的分数的更多信息(例如,玩家是否在所有玩家的前 12% 之内),请调用 Scores.get。
如果您正在调试游戏,则可以从管理 API 调用 Scores.reset,重置该玩家在特定排行榜中的所有分数。