啟用 Google Play 遊戲服務的伺服器端存取權

如果您的遊戲使用後端伺服器,建議您使用後端伺服器 Google 登入驗證玩家和 將玩家的身分安全地傳遞至後端伺服器這也能 即可安全地擷取玩家身分和其他資料 可能遭到裝置竄改

在這種情況下,遊戲會照常提示玩家登入 Google Play 遊戲服務。當 玩家成功登入,GoogleSignInAccount 物件會包含一組一次性特殊程式碼 (稱為「伺服器驗證碼」)。接著,在伺服器交換 使用 OAuth 2.0 權杖的伺服器驗證碼,伺服器可用來呼叫 Google Play 遊戲服務 API。

如需在遊戲中加入登入的其他指引,請參閱 登入 Android 遊戲

如要查看詳細的程式碼範例,瞭解如何使用 Google 登入來驗證玩家,請參閱 GitHub 上的 clientserverskeleton 範例

離線存取必須採取以下步驟:

  1. 在 Google Play 管理中心:建立遊戲伺服器的憑證。 憑證的 OAuth 用戶端類型為「網站」。
  2. 在 Android 應用程式:在登入時要求取得伺服器憑證的伺服器驗證碼,然後將該驗證碼傳遞至伺服器。
  3. 在遊戲伺服器上:交換伺服器驗證碼以取得 OAuth 存取權 權杖,然後使用這組權杖呼叫 Play 遊戲服務 REST API

事前準備

您必須先將 Google 登入功能整合到遊戲中, Google Play 管理中心, 請參閱「設定 Google Play 遊戲服務」一文。

為遊戲建立相關聯的伺服器端網頁應用程式

Google Play 遊戲服務不提供後端功能 支援網頁遊戲但是它會提供後端伺服器支援 以便擷取 YAML 檔案

如要使用 Google Play 遊戲服務的 REST API ,請按照下列步驟操作:

  1. 在以下項目的「已連結的應用程式」部分中,為遊戲建立相關聯的網頁應用程式 Google Play 管理中心。請注意, launch_url 未用於此流程,可以留空。
  2. 如要取得應用程式的憑證資訊,請按照下列步驟操作:
    1. 在 Google Play 管理中心的遊戲中,按一下「遊戲詳細資料」
    2. 向下捲動到「API 主控台專案」部分,然後按一下連結 API 控制台專案
    3. 透過 API 與服務 >Google API 中的憑證憑證畫面 控制台,下載網頁應用程式的 client_secret.json 檔案 並儲存到伺服器可以存取的位置。記錄用戶端 供日後參照的憑證 ID。
  3. 重新啟動伺服器端應用程式,以便接受從 用戶端應用程式的要求。

在用戶端執行登入

GoogleSignInClient 類別是主要進入點,可擷取目前 以及登入玩家 (如果先前未在) 在應用程式中登入的播放器, 裝置。

如要建立登入用戶端,請按照下列步驟操作:

  1. 透過 GoogleSignInOptions 物件建立登入用戶端。在 如要設定登入流程,您必須指定 GoogleSignInOptions.Builder GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN
  2. 此外,您也必須指明遊戲要求使用者必須通過驗證 方法是呼叫 GoogleSignInOptions.Builder.requestServerAuthCode() 方法,伺服器用戶端 ID 為 參數。您稍後會擷取驗證碼以取得後端伺服器上的存取權杖,如所述 「取得伺服器驗證碼」一節。
  3. 呼叫 GoogleSignIn.getClient() 方法,並傳遞先前設定的選項。如果來電 成功後,Google Sign-In API 會傳回 GoogleSignInClient 的執行個體。
  4. 取得 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);
}

取得伺服器驗證碼

如要擷取遊戲在後端伺服器取得存取權杖使用的伺服器驗證碼, 呼叫 getServerAuthCode() GoogleSignInAccount 中的方法 玩家成功登入時,Google 登入會傳回的物件。

範例如下:


// 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 Games Services 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

請參閱「Google Play 遊戲服務的 REST API」一文 可用 API 呼叫的完整說明。

以下是幾個實用的 REST API 呼叫範例,歡迎參考:

球員

  • 想要取得已登入玩家的 ID 和設定檔資料嗎?呼叫 Players.get'me' 做為 ID

朋友

請務必詳閱「好友」指南,其中有「好友」的詳細說明。

成就

請務必詳閱「成就」指南,其中說明成就的 一起來看看吧

排行榜

請務必詳閱「排行榜」指南,其中有排行榜的詳細說明。

  • 想要取得遊戲中所有計分板的清單嗎?呼叫 Leaderboards.list
  • 玩家是否已經完成遊戲?你可以在 Scores.submit 瞭解他們的分數,瞭解他們是否 這是新的最高分
  • 要顯示排行榜嗎?從 Scores.list 取得資料,並向使用者顯示。
  • 使用 Scores.listWindow 找出接近使用者最高分的分數。
  • 如要進一步瞭解特定排行榜中的玩家得分 (例如, 是所有玩家排名前 12% 的玩家,請呼叫 Scores.get
  • 您要為遊戲偵錯嗎?請嘗試透過管理頁面呼叫 Scores.reset 可透過 API 重設該玩家的所有分數