如果您的游戏使用后端服务器,我们建议您使用 Google 登录 来验证玩家身份,并将玩家身份安全地传递到后端服务器。这还使您的游戏能够安全地检索玩家身份和其他数据,而不会在通过设备时暴露于潜在的篡改。
在这种情况下,您的游戏会像往常一样提示玩家登录 Google Play 游戏服务。当玩家成功登录后,GoogleSignInAccount
对象包含一个特殊的单次使用代码(称为服务器授权代码),客户端将其传递给服务器。然后,在服务器上,将服务器授权代码交换为 OAuth 2.0 令牌,服务器可以使用该令牌调用 Google Play 游戏服务 API。
有关在游戏中添加登录的更多指导,请参阅 Android 游戏中的登录。
要查看显示如何使用 Google 登录来验证玩家身份的详细代码示例,请参阅 GitHub 上的 clientserverskeleton
示例。
脱机访问需要以下步骤
- 在 Google Play Console 中:为您的游戏服务器创建凭据。凭据的 OAuth 客户端类型将为“网络”。
- 在 Android 应用中:作为登录的一部分,为服务器的凭据请求服务器授权代码,并将其传递给您的服务器。
- 在您的游戏服务器上:使用 Google 身份验证服务将服务器授权代码交换为 OAuth 访问令牌,然后使用它来调用 Play 游戏服务的 REST API。
开始之前
在将 Google 登录集成到您的游戏中之前,您首先需要在 Google Play Console 中添加您的游戏,如 设置 Google Play 游戏服务 中所述。
为您的游戏创建关联的服务器端网络应用
Google Play 游戏服务不提供对 Web 游戏的后端支持。但是,它确实为您的 Android 游戏的服务器提供后端服务器支持。
如果您想在服务器端应用中使用 Google Play 游戏服务的 REST API,请按照以下步骤操作
- 在 Google Play Console 的**关联应用**部分中为您的游戏创建一个关联的网络应用。请注意,此流程不使用
launch_url
,可以将其留空。 - 要获取应用的凭据信息,请按照以下步骤操作
- 在 Google Play Console 中的您的游戏中,点击**游戏详情**。
- 向下滚动到**API 控制台项目**部分,然后点击 API 控制台项目的链接。
- 在 Google API Console 的**API 和服务 > 凭据**屏幕中,下载您的网络应用的
client_secret.json
文件并将其保存到服务器可以访问的位置。记录凭据的客户端 ID 以备后用。
- 重新启动您的服务器端应用,使其准备好接收来自游戏客户端应用的请求。
在客户端执行登录
GoogleSignInClient
类是检索当前已登录玩家的帐户以及在玩家尚未在设备上的应用中登录的情况下登录玩家的主要入口点。
要创建登录客户端,请按照以下步骤操作
- 通过
GoogleSignInOptions
对象创建登录客户端。在GoogleSignInOptions.Builder
中配置您的登录时,必须指定GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN
。 - 您还必须通过调用
GoogleSignInOptions.Builder.requestServerAuthCode()
方法(服务器的客户端 ID 作为参数)来指定您的游戏需要后端服务器的授权码。您稍后将检索授权码,以便在后端服务器上获取访问令牌,如获取服务器授权码中所述。 - 调用
GoogleSignIn.getClient()
方法并传入您之前配置的选项。如果调用成功,Google Sign-In API 将返回GoogleSignInClient
的实例。 - 获得
GoogleSignInClient
实例后,您应该从活动的onResume()
方法中静默登录玩家,如执行静默登录中所述。
这是一个示例
private static final int RC_SIGN_IN = 9001; private GoogleSignInClient mGoogleSignInClient; private void startSignInForAuthCode() { // Client ID for your backend server. String webClientId = getString(R.string.webclient_id); GoogleSignInOptions signInOption = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN) .requestServerAuthCode(webClientId) .build(); GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption); Intent intent = signInClient.getSignInIntent(); startActivityForResult(intent, RC_SIGN_IN); }
获取服务器授权码
要检索游戏可用于后端服务器访问令牌的服务器授权码,请在 Google Sign-In 在玩家成功登录后返回的 GoogleSignInAccount
对象上调用 getServerAuthCode()
方法。
这是一个示例
// Auth code to send to backend server. private String mServerAuthCode; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); if (result.isSuccess()) { mServerAuthCode = result.getSignInAccount().getServerAuthCode(); } else { String message = result.getStatus().getStatusMessage(); if (message == null || message.isEmpty()) { message = getString(R.string.signin_other_error); } new AlertDialog.Builder(this).setMessage(message) .setNeutralButton(android.R.string.ok, null).show(); } } }
在服务器上将服务器授权码交换为访问令牌
将服务器授权码发送到您的后端服务器以交换访问令牌和刷新令牌。使用访问令牌代表玩家调用 Google 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 should not 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;
}
要了解有关代表已登录玩家从后端服务器访问 Google API 的更多信息,请参阅 启用服务器端访问。
处理玩家注销
要将玩家注销出您的游戏,请在 GoogleSignInClient
上调用 signOut()
方法。有关示例代码片段,请参阅 注销玩家。
从服务器调用 REST API
有关可用的 API 调用的完整说明,请参阅 Google Play 游戏服务的 REST API。
您可能会发现以下 REST API 调用的示例很有用
玩家
- 想要获取已登录玩家的 ID 和个人资料数据?使用
'me'
作为 ID 调用 Players.get。
好友
请务必查看 好友 指南,其中更详细地解释了好友。
- 想要检索玩家的好友列表?使用
'friends_all'
作为collection
调用 Players.list。 - 检查您是否有权访问好友列表?对
me
调用 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 以重置特定排行榜中该玩家的所有分数。