在 Android 遊戲中登入

您的遊戲必須提供已登入玩家的帳戶,才能使用 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() 授予必要的權限。如果兩個條件都為 true (也就是 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() 來取得包含詳細狀態碼的 ApiExceptionCommonStatusCodes.SIGN_IN_REQUIRED 狀態碼表示玩家需要採取明確行動才能登入。在這種情況下,您的應用程式應啟動互動式登入流程,如下一節所述。

執行互動式登入

如要登入玩家互動,您的應用程式必須啟動登入意圖。如果成功,Google Sign-In 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 Sign-In 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.
        }
      });
}