如果您的遊戲使用後端伺服器,建議您使用 Google 登入來驗證玩家,並安全地將玩家的身分傳送至後端伺服器。如此一來,您的遊戲還能安全地擷取玩家的身分及其他資料,而無需在裝置遭傳輸時受到潛在竄改。
在這種情況下,您的遊戲會照常提示玩家登入 Google Play 遊戲服務。玩家成功登入後,GoogleSignInAccount
物件會包含特殊的單次使用代碼 (稱為「伺服器驗證碼」),以供用戶端傳遞至伺服器。然後在伺服器上交換 OAuth 2.0 憑證的伺服器驗證碼,讓伺服器用來呼叫 Google Play Games Services API。
如需在遊戲中新增登入的其他指引,請參閱在 Android 遊戲中登入。
如要查看如何使用 Google 登入功能驗證玩家的詳細程式碼範例,請參閱 GitHub 上的 clientserverskeleton
範例。
離線存取必須採取以下步驟:
- 在 Google Play 管理中心:為遊戲伺服器建立憑證。憑證的 OAuth 用戶端類型為「網站」。
- 在 Android 應用程式中:登入時要求取得伺服器憑證的伺服器驗證碼,然後將該驗證碼傳遞至伺服器。
- 您的遊戲伺服器:以 Google 驗證服務交換 OAuth 存取憑證的伺服器驗證碼,然後用來呼叫 Play 遊戲服務 REST API。
事前準備
將 Google 登入功能整合至您的遊戲之前,您必須先在 Google Play 管理中心新增遊戲,詳情請參閱設定 Google Play 遊戲服務的說明。
為遊戲建立相關的伺服器端網路應用程式
Google Play 遊戲服務無法提供網路遊戲的後端支援,但是會提供 Android 遊戲伺服器的後端伺服器支援。
如果要在伺服器端應用程式中使用 Google Play 遊戲服務的 REST API,請按照以下步驟操作:
- 在 Google Play 管理中心的「已連結的應用程式」部分中為遊戲建立相關聯的網路應用程式。請注意,此流程不會使用
launch_url
,但也可以留空。 - 如要取得應用程式的憑證資訊,請按照下列步驟操作:
- 在 Google Play 管理中心的遊戲中,按一下 [遊戲詳細資訊]。
- 向下捲動至「API 主控台專案」部分,然後按一下 API 控制台專案的連結。
- 在 Google API 控制台的「API 和服務」>「憑證」畫面中,下載網路應用程式的
client_secret.json
檔案,然後儲存到伺服器可存取的位置。記下憑證的用戶端 ID 以供日後參考。
- 重新啟動伺服器端應用程式,以便接受來自遊戲用戶端應用程式的要求。
在用戶端執行登入作業
GoogleSignInClient
類別是擷取目前登入玩家帳戶的主要進入點;如果之前裝置上未在裝置上執行過應用程式,則用來登入玩家。
建立登入用戶端的步驟如下:
- 透過
GoogleSignInOptions
物件建立登入用戶端。在GoogleSignInOptions.Builder
中設定登入時,您必須指定GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN
。 - 您還必須透過呼叫伺服器用戶端 ID 做為參數的
GoogleSignInOptions.Builder.requestServerAuthCode()
方法,指定遊戲需要後端伺服器的驗證碼。您稍後將在您的後端伺服器上擷取存取權杖的驗證碼,如取得伺服器驗證碼一節所述。 - 呼叫
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); }
取得伺服器驗證碼
如要擷取遊戲在後端伺服器上用於存取存取憑證的伺服器驗證碼,請針對成功登入的使用者所傳回的 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 和設定檔資料嗎?呼叫 Players.get 並使用
'me'
做為 ID。
朋友
請務必查看好友指南,進一步瞭解好友。
- 想要擷取玩家的好友名單嗎?呼叫 Players.list,
'friends_all'
collection
。 - 確認您是否能夠存取好友名單?呼叫
me
的 Players.get,並查看回應中的profileSettings.friendsListVisibility
欄位。
成就
請務必詳閱成就指南,其中會進一步說明各項成就。
- 想查看目前的成就清單嗎?您可以呼叫 AchievementDefinitions.list。
- 再加入 Achievements.list 呼叫,找出玩家在哪些裝置上解鎖。
- 玩家能否贏得成就?使用 Achievements.unlock 即可解鎖!
- 玩家能否取得部分成就?使用 Achievements.增量 回報進度 (以及判斷玩家是否成功解鎖)。
- 您正針對尚未正式發布的遊戲進行偵錯嗎?請嘗試透過 Management API 呼叫 Achievements.reset 或 Achievements.resetAll,將成就重設為原始狀態。
排行榜
請務必參閱排行榜指南,進一步瞭解排行榜的詳細資訊。
- 想要取得遊戲中所有計分板的清單嗎?呼叫 排行榜 s.list。
- 玩家完成遊戲了嗎?您可以將他們的分數提交至 Scores.submit,看看這是否為新的高分。
- 想要顯示排行榜嗎?從 Scores.list 取得資料並向使用者顯示。
- 使用 Scores.listWindow 尋找接近使用者最高分的分數。
- 如要進一步瞭解特定排行榜中玩家的分數 (例如,假設玩家在前 12% 的排行榜中),請呼叫 Scores.get。
- 您是否正在對遊戲進行偵錯?嘗試透過 Management API 呼叫 Scores.reset,重設特定排行榜中該玩家的所有分數