登入 Android 遊戲

Google 登入 API 淘汰後,我們將於 2026 年移除遊戲服務第 1 版 SDK。2025 年 2 月後,新整合遊戲服務第 1 版 SDK 的遊戲將無法在 Google Play 發布,建議改用遊戲服務第 2 版 SDK。
雖然整合舊版遊戲第 1 版的現有遊戲仍可運作幾年,但我們建議您自 2025 年 6 月起遷移至第 2 版
本指南適用於 Play 遊戲服務第 1 版 SDK。如要瞭解最新版 SDK,請參閱 第 2 版說明文件

如要存取 Google Play 遊戲服務功能,遊戲必須提供已登入玩家的帳戶。如果玩家未通過驗證,遊戲在呼叫 Google Play 遊戲服務 API 時可能會發生錯誤。本文件說明如何在遊戲中實作順暢的登入體驗。

實作玩家登入功能

GoogleSignInClient 類別是主要進入點,可擷取目前登入玩家的帳戶,並在玩家先前未在裝置上登入應用程式時,登入玩家帳戶。

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

  1. 透過 GoogleSignInOptions 物件建立登入用戶端,如以下程式碼片段所示。如要在 GoogleSignInOptions.Builder 中設定登入,您必須指定 GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN

    GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
  2. 如要使用 SnapshotsClient,請將 .requestScopes(Games.SCOPE_GAMES_SNAPSHOTS) 新增至 GoogleSignInOptions.Builder,如下列程式碼片段所示:

    GoogleSignInOptions  signInOptions =
        new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
            .requestScopes(Games.SCOPE_GAMES_SNAPSHOTS)
            .build();
  3. 呼叫 GoogleSignIn.getClient() 方法,並傳入您在先前步驟中設定的選項。如果呼叫成功,Google 登入 API 會傳回 GoogleSignInClient 的例項。

檢查播放器是否已登入

您可以使用 GoogleSignIn.getLastSignedInAccount() 檢查目前裝置是否已登入帳戶,並使用 GoogleSignIn.hasPermissions() 檢查該帳戶是否已獲得必要權限。如果兩個條件都成立,也就是 getLastSignedInAccount() 傳回非空值,且 hasPermissions() 傳回 true,即使裝置處於離線狀態,您也可以安全地使用 getLastSignedInAccount() 傳回的帳戶。

執行自動登入

您可以呼叫 silentSignIn() 擷取目前登入玩家的帳戶,並嘗試登入玩家,如果玩家已在其他裝置上成功登入您的應用程式,則無須顯示使用者介面。

silentSignIn() 方法會傳回 Task<GoogleSignInAccount>。工作完成後,請將先前宣告的 GoogleSignInAccount 欄位設為工作傳回的登入帳戶,或設為 null,表示沒有登入的使用者。

如果無聲登入嘗試失敗,您可以選擇傳送登入意圖來顯示登入使用者介面,如「執行互動式登入」一文所述。

由於活動不在前景時,登入玩家的狀態可能會變更,因此建議從活動的 onResume() 方法呼叫 silentSignIn()

如要以無聲方式登入,請按照下列步驟操作:

  1. GoogleSignInClient 上呼叫 silentSignIn() 方法,啟動無聲登入流程。 如果無聲登入成功,這個呼叫會傳回包含 GoogleSignInAccountTask<GoogleSignInAccount> 物件。
  2. 覆寫 OnCompleteListener,處理玩家登入成功或失敗的情況。

以下程式碼片段將展示應用程式如何執行無聲登入:

private void signInSilently() {
  GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
  GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
  if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())) {
    // Already signed in.
    // The signed in account is stored in the 'account' variable.
    GoogleSignInAccount signedInAccount = account;
  } else {
    // Haven't been signed-in before. Try the silent sign-in first.
    GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOptions);
    signInClient
        .silentSignIn()
        .addOnCompleteListener(
            this,
            new OnCompleteListener<GoogleSignInAccount>() {
              @Override
              public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                if (task.isSuccessful()) {
                  // The signed in account is stored in the task's result.
                  GoogleSignInAccount signedInAccount = task.getResult();
                } else {
                  // Player will need to sign-in explicitly using via UI.
                  // See [sign-in best practices](http://developers.google.com/games/services/checklist) for guidance on how and when to implement Interactive Sign-in,
                  // and [Performing Interactive Sign-in](http://developers.google.com/games/services/android/signin#performing_interactive_sign-in) for details on how to implement
                  // Interactive Sign-in.
                }
              }
            });
  }
}

@Override
protected void onResume() {
  super.onResume();
  signInSilently();
}

如果無聲登入嘗試失敗,您可以呼叫 getException() 取得 ApiException,其中包含詳細的狀態碼。狀態碼 CommonStatusCodes.SIGN_IN_REQUIRED 表示玩家必須採取明確行動才能登入。在這種情況下,應用程式應啟動互動式登入流程,如下一節所述。

執行互動式登入

如要透過玩家互動登入,應用程式必須啟動登入意圖。如果成功,Google 登入 API 會顯示使用者介面,提示玩家輸入憑證登入。這種做法可簡化應用程式開發作業,因為登入活動會代表應用程式處理需要更新 Google Play 服務或顯示同意提示等情況。結果會透過 onActivityResult 回呼傳回。

如要以互動方式登入,請按照下列步驟操作:

  1. GoogleSignInClient 上呼叫 getSigninIntent() 取得登入意圖,然後呼叫 startActivity() 並傳入該意圖。下列程式碼片段說明應用程式如何啟動互動式登入流程:

    private void startSignInIntent() {
      GoogleSignInClient signInClient = GoogleSignIn.getClient(this,
          GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
      Intent intent = signInClient.getSignInIntent();
      startActivityForResult(intent, RC_SIGN_IN);
    }
  2. onActivityResult() 回呼中,處理傳回意圖的結果。

    • 如果登入成功,請從 GoogleSignInResult 取得 GoogleSignInAccount 物件。
    • 如果登入失敗,您應處理登入錯誤 (例如在快訊中顯示錯誤訊息)。以下程式碼片段說明應用程式如何處理玩家登入結果:
    @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()) {
          // The signed in account is stored in the result.
          GoogleSignInAccount signedInAccount = result.getSignInAccount();
        } 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 登入 API 傳回的 GoogleSignInAccount 不含任何玩家資訊。如果遊戲會使用玩家資訊 (例如玩家顯示名稱和玩家 ID),請按照下列步驟擷取這類資訊。

  1. 呼叫 getPlayersClient() 方法,並傳入 GoogleSignInAccount 做為參數,即可取得 PlayersClient 物件。
  2. 使用 PlayersClient 方法,以非同步方式載入包含玩家資訊的 Player 物件。舉例來說,您可以呼叫 getCurrentPlayer() 載入目前登入的玩家。如果工作傳回狀態碼為 SIGN_IN_REQUIREDApiException,表示播放器需要重新驗證。如要執行這項操作,請呼叫 GoogleSignInClient.getSignInIntent(),以互動方式登入播放器。
  3. 如果工作成功傳回 Player 物件,您就可以呼叫 Player 物件的方法,擷取特定玩家詳細資料 (例如 getDisplayName()getPlayerId())。

提供登入按鈕

如要在遊戲中提供標準的 Google 登入按鈕,可以採用下列其中一種做法:

使用者點選登入按鈕後,遊戲應如「執行互動式登入」一文所述,傳送登入意圖來啟動登入流程。

這段程式碼片段說明如何在活動的 onCreate() 方法中新增登入按鈕。

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_sign_in);
  findViewById(R.id.sign_in_button).setOnClickListener(this);
  findViewById(R.id.sign_out_button).setOnClickListener(this);
}

下列程式碼片段說明使用者點選登入按鈕時,如何傳送登入意圖。

@Override
public void onClick(View view) {
  if (view.getId() == R.id.sign_in_button) {
    // start the asynchronous sign in flow
    startSignInIntent();
  } else if (view.getId() == R.id.sign_out_button) {
    // sign out.
    signOut();
    // show sign-in button, hide the sign-out button
    findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
    findViewById(R.id.sign_out_button).setVisibility(View.GONE);
  }
}

顯示遊戲彈出式視窗

您可以使用 GamesClient 類別,在遊戲中顯示彈出式檢視區塊。例如,遊戲可以顯示「歡迎回來」或「已解鎖成就」彈出式視窗。如要允許 Google Play 遊戲服務在遊戲的檢視區塊中啟動彈出式視窗,請呼叫 setViewForPopups() 方法。呼叫 setGravityForPopups(),即可進一步自訂彈出式視窗在畫面中的顯示位置。

登出玩家

如要登出,請在 GoogleSignInClient 上呼叫 signOut() 方法。

private void signOut() {
  GoogleSignInClient signInClient = GoogleSignIn.getClient(this,
      GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
  signInClient.signOut().addOnCompleteListener(this,
      new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
          // at this point, the user is signed out.
        }
      });
}